Acessar dispositivos e metadados de dispositivos para iOS

As APIs de dispositivo podem ser acessadas pelas APIs Home para iOS. Importe os seguintes pacotes para seu app:

import GoogleHomeSDK
import GoogleHomeTypes

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

Tratamento de erros

Alguns métodos nas APIs Home geram um HomeError. Por isso, recomendamos que você use um do-catch bloco para detectar HomeError nessas chamadas.

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

Qualquer erro não tratado vai resultar em falha do app.

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

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

Exemplos de chamadas

Acessar uma lista de dispositivos

Com uma referência ao Home objeto, invoque devices() para receber uma Query de dispositivos acessíveis. Chame o método Query's batched(), que emite um conjunto refletindo o estado atual da casa com cada mudança de metadados do dispositivo. Ou chame Query.list() para receber um snapshot dos dispositivos disponíveis. Esse é um método de conveniência que se inscreve no stream batched() e retorna o primeiro valor emitido. Query.stream() produz um stream que emite novos valores em mudanças de metadados do dispositivo, como nome, sala ou estrutura. Internamente, ele usa batched() e emite apenas as propriedades alteradas.

// Get a list of all devices accessible to the user
let homeDevices = try await self.home.devices().list()

A partir daí, você pode acessar os estados de cada dispositivo e enviar comandos a eles.

Com a versão 1.8 das APIs Home, você tem a opção de fazer com que a API represente cada dispositivo multipartes como um único dispositivo definindo o parâmetro enableMultipartDevices do método devices() como true. Consulte Dispositivos multipartes no iOS para mais informações.

Acessar os tipos de dispositivo

Para acessar os tipos de dispositivo associados a um dispositivo, leia a propriedade types, que retorna um DeviceTypeController.

Chame DeviceTypeController.subscribe(_:) para se inscrever em atualizações de um tipo de dispositivo específico:

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

Se o dispositivo não oferecer suporte ao tipo especificado, ele vai retornar um Empty Publisher que será concluído imediatamente.

Se o dispositivo oferecer suporte a um tipo específico, você poderá receber um identificador desse tipo chamando get():

if let device = devices.first(where: { $0.id == myDeviceId }) {
  let _ = await device.types.get(OnOffLightDeviceType.self)
}

Se o dispositivo não oferecer suporte ao tipo especificado, ele vai retornar nil.

Chame DeviceTypeController.subscribeAll() para receber um Publisher de DeviceTypeCollection. Essa classe permite verificar se o dispositivo tem um tipo específico:

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

Acessar uma característica de tipo de dispositivo

Os tipos de dispositivo são o ponto de entrada para a leitura de características, já que decompõem um dispositivo em partes funcionais (como endpoints no Matter).

Eles também consideram colisões de características caso um dispositivo tenha dois tipos, ambos com a mesma característica. Por exemplo, se um dispositivo for um alto-falante e uma luz regulável, ele terá duas características de ligar/desligar e duas de controle de nível.

Outro tipo de colisão de características pode ocorrer quando um dispositivo tem duas características 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 de uma característica OnOff definida pelo fabricante. Para eliminar qualquer ambiguidade em relação a qual característica é pretendida, faça referência a uma característica por uma das duas coleções de características em cada tipo de dispositivo.

Para características padrão, ou seja, aquelas análogas aos Matter clusters padrão, use matterTraits. Por exemplo, para receber uma característica específica para o tipo de dispositivo de luz regulável:

if let dimmableLightDeviceType =
  await device.types.get(DimmableLightDeviceType.self)
{
  // Accessing standard trait on the type.
  let levelControlTrait =
    dimmableLightDeviceType.matterTraits.levelControlTrait.self
}

Para características do Google, use googleTraits:

if let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) {
  // Accessing Google trait on the type.
  let doorbellPressTrait =
    doorbellDeviceType.traits[Google.DoorbellPressTrait.self]
}

Para acessar uma característica específica do fabricante, faça referência a ela pela propriedade traits, mas preceda-a com o nome do pacote do fabricante:

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
}

Ler o estado de um dispositivo

Confira este exemplo de verificação do atributo OnOff da característica de ligar/desligar do dispositivo:

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
}

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

Para acessar uma lista de dispositivos que têm uma característica específica, é necessário iterar sobre os dispositivos, os tipos de dispositivo de cada um e as características de cada tipo. Por exemplo, para acessar uma lista de dispositivos na casa que têm a característica de ligar/desligar:

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

Consulte Índice de características no iOS para uma lista completa de características disponíveis nas APIs Home.

Acessar uma lista de dispositivos com tipos semelhantes

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

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

Há vários tipos de dispositivo 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 diferentes de dispositivos que podem representar uma luz, conforme mostrado no exemplo anterior. Assim, para ter uma visão abrangente do tipo de dispositivo de nível superior em uma casa, é necessário incluir vários tipos de dispositivo.

Consulte Tipos de dispositivo compatíveis no iOS para uma lista completa de tipos de dispositivo e características disponíveis nas APIs Home.

Acessar o nome, o ID do fornecedor ou o ID do produto de um dispositivo

A característica BasicInformationTrait inclui informações como ID do fornecedor, ID do produto, nome do produto e o número de série de um dispositivo:

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

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

Se você é um fabricante de dispositivos e cria Cloud-to-cloud dispositivos, para identificar seus Cloud-to-cloud dispositivos pela BasicInformation característica, inclua estes campos de string na resposta SYNC:

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

  • Um identificador de produto que identifica exclusivamente 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 disponíveis. Se você não for membro e não tiver recebido esses IDs, deixe os campos matterOriginalVendorId e matterOriginalProductId em branco e forneça o matterUniqueId como identificador.Alliance

O exemplo de resposta 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 Cloud-to-cloud SYNC.

Metadados de dispositivo e característica

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 sourceConnectivity propriedade, que tem informações sobre o status on-line e a localidade de uma característica (roteamento local ou remoto).

Acessar o tipo principal de um dispositivo

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

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

Verificar se uma característica está on-line

Leia a propriedade connectivityState para verificar a conectividade de uma característica:

let levelControlConnectivity =
  levelControlTrait.metadata.sourceConnectivity
  .connectivityState

Algumas características, normalmente as do Google smart home, podem aparecer off-line se o dispositivo não tiver conectividade com a 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 dispositivos oferecem suporte a vários tipos. O estado retornado é uma combinação dos estados de conectividade de todas as características desse dispositivo.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

Um estado de partiallyOnline pode ser observado no caso de tipos de dispositivo mistos quando não há conectividade com a Internet. Matter As características padrão do Matter ainda podem estar on-line devido ao roteamento local, mas as características baseadas na nuvem estarão 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 ponto a ponto (diretamente do dispositivo para o dispositivo, sem hub).

O valor de localidade desconhecido unspecified é possível, por exemplo, enquanto um app está sendo inicializado e ainda não atingiu 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.

let levelControlLocality =
  levelControlTrait.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 desse dispositivo.

let lightLocality =
  dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality

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

Mudar o nome de um dispositivo

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

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

Ao mudar o nome de um dispositivo, a struct HomeDevice original permanece a mesma, e a mudança é refletida no objeto HomeDevice atualizado retornado.

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.