Controlar dispositivos no iOS

Este guia continua de Acesso a dispositivos e metadados de dispositivos no iOS e apresenta outros exemplos de controle e acesso a dispositivos.

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

import GoogleHomeSDK
import GoogleHomeTypes

Verificar se um trait oferece suporte a um comando

Use a função supports no nível do atributo para verificar se um comando tem suporte para um dispositivo específico.

Por exemplo, para verificar se um dispositivo oferece suporte ao comando toggle da característica Ligado/Desligado:

// 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 um recurso. Para ligar ou desligar o dispositivo, use o comando OnOffTrait "Toggle", 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 corretamente essas exceções e mostrar informações detalhadas aos usuários nos casos em que os erros podem ser úteis. Exceções não tratadas vão interromper o tempo de execução do app e poderão causar falhas nele.

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 app.

Enviar um comando com parâmetros

Alguns comandos podem usar parâmetros, como os do 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 um atributo é 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 que foi mapeado para Matter pode não oferecer suporte a todos os atributos Matter. Para lidar com casos como esses, use a propriedade isSupported no nível do atributo para verificar se o atributo tem suporte para um dispositivo específico.

Por exemplo, para verificar se um dispositivo oferece suporte ao atributo onOff da característica Ligado/Desligado:

// 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, usando 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 determinado atributo e nenhum dos comandos da traço fizer isso, o atributo poderá ter o valor 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 efeito colateral do envio de um comando de atributo?

A documentação de referência de 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 do SwitchTrait.

  • Somente leitura e afetado por outros comandos. Isso significa que a única maneira de mudar o valor do atributo é como resultado do envio de um comando. Por exemplo, o atributo currentLevel do LevelControlTrait é somente leitura, mas o valor dele pode ser modificado 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 do atributo, mas não há comandos que afetem o valor do atributo. Por exemplo, o atributo WrongCodeEntryLimit do DoorLockTrait.

  • Pode ser gravado e afetado por outros comandos. Isso significa que você pode mudar diretamente o valor do atributo usando a função update do atributo, 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 atributo DoorLockTrait.wrongCodeEntryLimit.

Para definir um valor de atributo, chame a função update do atributo e transmita uma função de atualização que defina o novo valor. É uma boa prática verificar primeiro se o atributo é compatível com o atributo.

Exemplo:

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