Acessar dispositivos e metadados deles

As APIs do dispositivo podem ser acessadas pelas APIs Home. Importe estes pacotes para o 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 tipo de dispositivo de unidade de plugue e o recurso Ligar/Desligar Matter, 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.

Tratamento de erros

Qualquer método nas APIs Home pode gerar uma 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 Como tratar erros.

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

Exemplos de chamadas

Receber uma lista de dispositivos

Com a estrutura disponível, uma chamada devices() retorna um fluxo de dispositivos acessível 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 para o dispositivo.

Ler o estado de um dispositivo

Confira um exemplo de verificação do atributo OnOff do traço de ativação/desativação do dispositivo. Usando o modelo de dados de atributos das APIs Home, em que esse atributo é identificado como OnOff, é possível extrair dados de atributos 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 atributo

A interface TraitStateInvalidation permite invalidar um estado recuperado por assinaturas no dispositivo de destino nos 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 características Matter com a qualidade "C" ou devido a uma implementação do dispositivo que causa o problema de forma inesperada.

Essa API emite uma leitura forçada do estado atual do atributo e retorna o resultado pelos fluxos de atributo atuais.

Receba o atributo e execute um forceRead nele:

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

Conferir uma lista de características do tipo de dispositivo

Os tipos de dispositivo precisam ser usados como um ponto de entrada para ler os traços, porque eles decompõem um dispositivo em partes funcionais (como endpoints em Matter).

Elas também consideram colisões de traços no caso de um dispositivo apresentar dois tipos de dispositivo, que podem ter o mesmo traço. Por exemplo, se um dispositivo for um alto-falante e uma luz regulável, ele terá duas características de ativação/desativação e duas de controle de nível.

Para conferir a lista de características disponíveis para o tipo de dispositivo de luz regulá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 colisão de recurso pode ocorrer quando um dispositivo tem dois recursos com o mesmo nome. Por exemplo, onOff pode se referir a uma instância do atributo OnOff padrão ou a uma instância de um atributo OnOff definido pelo fabricante. Para eliminar qualquer ambiguidade em relação ao tipo de traço, uma instância Trait referenciada por um dispositivo precisa ser precedida por um namespace qualificado. Para características padrão, ou seja, aquelas que são análogas aos clusters padrão Matter, use standardTraits. Para os atributos do Google, use googleTraits:

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

Para acessar um atributo específico do fabricante, faça referência a ele diretamente:

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

Conseguir uma lista de dispositivos com um recurso específico

A função filter no Kotlin pode ser usada para refinar ainda mais as chamadas de API. Por exemplo, para receber uma lista de dispositivos na casa que têm o atributo "Ligado/Desligado":

// 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 conferir uma lista completa de características disponíveis nas APIs Home.

Conseguir uma lista de dispositivos com tipos semelhantes

Para conferir 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 do Google Home que podem representar um tipo principal de dispositivo. Por exemplo, não há um tipo de dispositivo "Luz". Em vez disso, há quatro tipos diferentes de dispositivo que podem representar uma luz, conforme mostrado no exemplo anterior. Portanto, para ter uma visão abrangente do tipo de dispositivo de nível superior em uma casa, vários tipos de dispositivo precisam ser incluídos nos fluxos filtrados.

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

Conferir o ID do fornecedor ou do produto de um dispositivo

O atributo BasicInformation inclui informações como ID do fornecedor, ID do produto, nome do produto e 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}")

Identificar dispositivos de nuvem para nuvem

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:

  • O ID do fornecedor emitido pela Connectivity Standards Alliance (CSA) é: "matterOriginalVendorId": "0xfff1",

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

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

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

O exemplo de resposta do SYNC mostra o uso desses 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 atributos

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

Cada atributo nas APIs Home contém uma propriedade sourceConnectivity, que tem informações sobre o status on-line e a localidade de um atributo (roteamento local ou remoto).

Conseguir o tipo principal de um dispositivo

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

Primeiro, receba os tipos do dispositivo usando type(), depois determine qual é o tipo principal:

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

Verificar se um atributo está on-line

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

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

Algumas características, geralmente as do Google smart home, podem aparecer off-line se o dispositivo não tiver conectividade de Internet. Isso ocorre porque essas características são baseadas 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 deles oferecem suporte a vários tipos. O estado retornado é uma combinação dos estados de conectividade de todos os traços no 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 de Internet. Os atributos padrão do Matter ainda podem estar on-line devido ao roteamento local, mas os atributos baseados na nuvem estão off-line.

Verificar o roteamento de rede de um atributo

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

O valor de localidade desconhecida UNSPECIFIED é possível, por exemplo, enquanto um app está sendo inicializado e ainda não alcançou um hub ou servidor para conectividade do dispositivo. Esses dispositivos não podem ser acessados e vão falhar nas 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 todos os atributos no dispositivo.

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

Um estado de MIXED pode ser observado em um cenário semelhante ao da conectividade PARTIALLY_ONLINE: algumas características são baseadas na nuvem, enquanto outras são locais.

Lista de APIs

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

API Descrição
devices() Receber 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:

API Descrição
allCandidates() Retorna todos os candidatos de automação para o dispositivo e os filhos dele.
candidates() Retorna todos os candidatos de automação para o dispositivo.
connectivityStateChanged A última vez 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 essas características.
getSourceConnectivity(trait) Receber metadados de um atributo específico. Retorna um SourceConnectivity.
has(trait) Verifique se o dispositivo oferece suporte ao atributo solicitado.
has(type) Se o dispositivo oferece suporte ao tipo fornecido.
id O ID exclusivo do sistema do dispositivo.
isInRoom Se o dispositivo estiver em um cômodo.
isInStructure Se o dispositivo estiver em uma estrutura.
isMatterDevice Se o dispositivo tiver suporte para Matter.
name O nome do dispositivo fornecido pelo usuário.
room() O ambiente ao qual 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, que representa os estados de conectividade agregados e a localidade de rede dos atributos 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 do tipo com as características preenchidas (quando disponíveis) para acesso direto. Sempre retorna um snapshot atualizado dos atributos.
types() Receba uma lista de todos os tipos disponíveis no dispositivo.