Controlar dispositivos no iOS

Este guia é uma continuação de Acessar dispositivos e metadados de dispositivos no iOS e apresenta outros exemplos de controle e acesso a dispositivos.

Para usar tipos ou características de dispositivos específicos, como o Matter OnOffTrait usado em muitos dos exemplos aqui, eles precisam ser importados:

import GoogleHomeSDK
import GoogleHomeTypes

Verificar se uma característica é compatível com um comando

Use a função supports no nível de traço para verificar se um comando é compatível com um dispositivo específico.

Por exemplo, para verificar se um dispositivo é compatível com o comando toggle da característica On/Off:

// Check if the OnOff trait supports the toggle command.
if onOffTraitTest.supportsToggleCommand {
  print("onOffTrait supports toggle command")
} else {
  print("onOffTrait does not support stateful toggle command")
}

Enviar um comando para um dispositivo

Enviar um comando é semelhante a ler um atributo de estado de uma característica. Para ligar ou desligar o dispositivo, use o comando OnOffTrait Alternar, que é definido no modelo de dados do ecossistema do Google Home como toggle(). Esse método muda onOff para false se for true ou para true se for false:

// Calling a command on a trait.
do {
  try await onOffTraitTest.toggle()
} catch let error as HomeError {
  // Code for handling the exception
}

Os comandos podem retornar uma exceção se um problema for detectado no fluxo de execução. Como desenvolvedor, use um bloco do-catch para processar essas exceções corretamente e mostrar informações detalhadas aos usuários nos casos em que os erros podem ser corrigidos. Exceções não processadas interrompem o tempo de execução do app e podem causar falhas no app.

Como alternativa, use os comandos off() ou on() para definir explicitamente o estado:

do {
  try await onOffTraitTest.off()
  try await onOffTraitTest.on()
} catch let error as HomeError {
  // Code for handling the exception
}

Depois de enviar um comando para mudar o estado, quando ele for concluído, você poderá ler o estado conforme descrito em Ler o estado de um dispositivo para processá-lo no seu app.

Enviar um comando com parâmetros

Alguns comandos podem usar parâmetros, como os em OnOffTrait ou LevelControlTrait:

offWithEffect

// Turn off the light using the DyingLight effect.
do {
  try await onOffTraitTest.offWithEffect(
    effectIdentifier: Matter.OnOffTrait.EffectIdentifierEnum.dyingLight,
    effectVariant: 0
  )
} catch let error as HomeError {
  // Code for handling the exception
}

moveToLevel

// Change the brightness of the light to 50%
do {
  try await levelControlTraitTest.moveToLevel(
    level: UInt8(127),
    transitionTime: 0,
    optionsMask: Matter.LevelControlTrait.OptionsBitmap(),
    optionsOverride: Matter.LevelControlTrait.OptionsBitmap()
  )
} catch let error as HomeError {
  // Code for handling the exception
}

Verificar se uma característica é compatível com um atributo

Alguns dispositivos podem oferecer suporte a uma característica Matter, mas não a um atributo específico. Por exemplo, um dispositivo Cloud-to-cloud mapeado para Matter pode não ser compatível com todos os atributos de Matter. Para lidar com casos como esses, use a propriedade isSupported no nível do traço para verificar se o atributo é compatível com um dispositivo específico.

Por exemplo, para verificar se um dispositivo é compatível com o atributo onOff da característica de ligar/desligar:

// Check if the OnOff trait supports the onOff attribute.
if onOffTrait.attributes.$onOff.isSupported {
  print("onOffTrait supports onOff state")
} else {
  print("onOffTrait is for a command only device!")
}

Alguns atributos são anuláveis na especificação Matter ou no esquema Cloud-to-cloud smart home. Para esses atributos, é possível determinar se um nil retornado pelo atributo é devido ao dispositivo não informar esse valor ou se o valor do atributo é realmente nil. Para isso, use isNullable além de isSupported:

// Check if a nullable attribute is set or is not supported.
if let deviceType = await device.types.get(OnOffLightDeviceType.self) {
  if let onOffTrait = deviceType.traits[Matter.OnOffTrait.self] {
    if onOffTrait.attributes.startUpOnOff == nil {
      if onOffTrait.attributes.$startUpOnOff.isSupported {
        print(
          "onOffTrait supports startUpOnOff and it is nil. Check the spec for the contextual meaning."
        )
      } else {
        print("onOffTrait does not support startUpOnOff!")
      }
    } else {
      print(
        "onOffTrait supports startUpOnOff and it is set to \(onOffTrait.attributes.startUpOnOff)"
      )
    }
  }
}

Atualizar atributos de traço

Se você quiser mudar o valor de um atributo específico, e nenhum dos comandos da característica fizer isso, o atributo poderá permitir que o valor seja definido explicitamente.

A possibilidade de mudar o valor de um atributo depende de dois fatores:

  • O atributo pode ser gravado?
  • O valor do atributo pode mudar como um efeito colateral do envio de um comando de traço?

A documentação de referência para traços e atributos fornece essas informações.

Portanto, as combinações de propriedades que determinam como o valor de um atributo pode ser alterado são:

  • Somente leitura e não afetado por outros comandos. Isso significa que o valor do atributo não muda. Por exemplo, o atributo currentPosition de SwitchTrait.

  • Somente leitura e afetado por outros comandos. Isso significa que a única maneira de o valor do atributo mudar é como resultado do envio de um comando. Por exemplo, o atributo currentLevel do LevelControlTrait é somente leitura, mas o valor dele pode ser alterado por comandos como moveToLevel.

  • Gravável e não afetado por outros comandos. Isso significa que você pode mudar diretamente o valor do atributo usando a função update da característica, mas não há comandos que afetem o valor do atributo. Por exemplo, o atributo WrongCodeEntryLimit de DoorLockTrait.

  • Gravável e afetado por outros comandos. Isso significa que você pode mudar diretamente o valor do atributo usando a função update da característica, e o valor do atributo pode mudar como resultado do envio de um comando. Por exemplo, o atributo occupiedCoolingSetpoint do ThermostatTrait pode ser gravado, mas também atualizado com o comando setpointRaiseLower.

Exemplo de uso da função de atualização para mudar o valor de um atributo

Este exemplo mostra como definir explicitamente o valor do DoorLockTrait.wrongCodeEntryLimit atributo.

Para definir um valor de atributo, chame a função update da característica e transmita a ela uma função de atualização que define o novo valor. É recomendável primeiro verificar se o traço aceita um atributo.

Exemplo:

if doorLockTraitTest.attributes.$wrongCodeEntryLimit.isSupported {
  let _ = try await doorLockTraitTest.update {
    $0.setWrongCodeEntryLimit(3)
  }
}