Estruturar APIs no iOS

As APIs Structure podem ser acessadas pelas APIs Home para iOS.

Para trabalhar com as APIs Structure, primeiro importe o pacote GoogleHomeSDK para seu app:

import GoogleHomeSDK

Tratamento de erros

Alguns métodos nas APIs Home geram uma HomeError. Por isso, recomendamos usar um bloco do-catch para capturar HomeError nessas chamadas.

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

Qualquer erro não processado vai resultar em falha no app.

Para mais informações, consulte Como processar erros.

API Structure

Home representa o gráfico da página inicial e é o ponto de entrada da API Structure. Ele fornece referências a estruturas, salas e dispositivos.

Structure representa uma estrutura no gráfico "Início". Ele fornece acesso a metadados de estrutura, como id e name.

Use structures() para receber todas as estruturas na sua conta. As estruturas são retornadas na forma de um Query, que oferece uma variedade de maneiras de consumir os dados:

API Descrição
stream() Retorna um Publisher que emite cada objeto individualmente conforme as mudanças ocorrem.
batched() Retorna um Publisher que emite o resultado atual como um Set de objetos. Cada Set emitido representa o estado atual do gráfico de objetos.
list() Retorna o resultado atual como um Set de objetos.

A chamada structures().list() pode não retornar imediatamente um conjunto válido de estruturas. Se o app for reativo e chamar stream() para se inscrever em todas as mudanças de estrutura para direcionar a interface, uma lista válida de estruturas será retornada. Há outras situações em que uma lista de estrutura vazia pode ser retornada, por exemplo, se o smartphone do usuário perder a conectividade ou se o usuário tiver revogado as permissões do app. É necessário processar esses casos no app.

@Published public private(set) var structures: [Structure] = []
private var structuresCancellable: AnyCancellable?

  self.structuresCancellable = home
    .structures()
    .batched()
    .receive(on: DispatchQueue.main)
    .map { Array($0) }
    .catch {
      Logger.error("Failed to load structures: \($0)")
      return Just([Structure]())
    }
    .assign(to: \.structures, on: self)

Exemplos de chamadas de estrutura

Receber um conjunto de estruturas

Chamar list() em um Query<Structure> retorna o conjunto de elementos mais recente:

// Get a stream of all structures accessible to the user
let allStructuresChanges = try await self.home.structures()
let allStructures = try? await allStructuresChanges.list()

Ao projetar um app reativo, use chamadas batched() e stream() em vez de list(), porque elas produzem dados automaticamente quando o gráfico principal muda.

Acessar propriedades da estrutura

Com a lista de estruturas em mãos, é possível acessar as propriedades delas:

// Get a stream of changes taking place on a structure.
let structureChanges = try await home.structures().list().filter { $0.id == structureID }

// Get a snapshot of the structure.
let structure = try await structureChanges.first!

// Get structure properties
print("id \(structure.id) ")
print("name \(structure.name) ")

Encontrar uma estrutura pelo nome

Se você souber o nome de uma estrutura, também poderá acessá-la usando a propriedade name:

do {
  structure1 = try await home.structures().list().first(where: { $0.name == "Main House" })
} catch let error as HomeError {
  // Code for handling the exception
}

A partir daí, é possível acessar as propriedades, os cômodos e os dispositivos de cada estrutura.

Trabalhar com várias estruturas

Para usar mais de uma estrutura, receba uma referência separada para cada uma delas:

var structure1: Structure!
var structure2: Structure!
do {
  structure1 = try await home.structures().list().first(where: { $0.name == "Main House" })
} catch let error as HomeError {
  // Code for handling the exception
}
do {
  structure2 = try await home.structures().list().first(where: { $0.name == "Guest Cottage" })
} catch let error as HomeError {
  // Code for handling the exception
}

Salas

Um ambiente contém um grupo de dispositivos. Um cômodo sempre faz parte de uma estrutura, e uma estrutura pode ter vários cômodos. A remoção de uma sala de uma estrutura não remove os dispositivos dessa sala da estrutura. No entanto, se o ambiente for excluído, os dispositivos nele serão desassociados.

Use Home.rooms() para extrair todos os ambientes da conta e, em seguida, use roomID = device.roomID para exibir os dispositivos correspondentes em cada ambiente.

self.home.rooms().batched()
  .combineLatest(self.home.devices().batched())
  .receive(on: DispatchQueue.main)
  .catch { error in
    Logger.error("Failed to load rooms and devices: \(error)")
    return Just((Set<Room>(), Set<HomeDevice>()))
  }
  .map { rooms, devices in
    var devicesByRoom = [Room: [HomeDevice]]()
    for room in rooms where room.structureID == currentStructureID {
      devicesByRoom[room] = devices.filter { $0.roomID == room.id }
    }
    return devicesByRoom
  }.assign(to: &self.$devicesByRoom)

Exemplos de chamadas do Room

Receber uma lista de salas

Usando a classe Home, você pode acessar uma lista de salas e as propriedades delas:

let allRoomsChanges = self.home.rooms()
let allRooms = try await allRoomsChanges.list()
let room = allRooms.first!
XCTAssertTrue(allRooms.contains(room))

print("id \(room.id) ")
print("name \(room.name) ")

Criar uma sala

Para criar um novo ambiente em um Structure:

let testName = "Test Room Name"
var newRoom: Room!
do {
  newRoom = try await structure.createRoom(name: testName)
  XCTAssertNotNil(newRoom)
} catch let error as HomeError {
  // Code for handling the exception
}

Excluir um ambiente

Também é possível excluir uma sala:

val roomToDelete = structure.rooms().list().filter { it.name == "room_id1" }.firstOrNull()
    structure.deleteRoom(roomToDelete!!)

Também é possível excluir uma sala usando o ID dela:

let roomToDelete = allRooms.first(where: { $0.id == room.id })
if let roomToDelete1 = roomToDelete {
  do {
    try await structure.deleteRoom(roomToDelete1)
  } catch let error as HomeError {
    // Code for handling the exception
  }
}

Se um ambiente com dispositivos for excluído, eles ainda estarão na estrutura, mas não serão mais atribuídos a um ambiente.

Mover dispositivos para outro ambiente

O Structure também permite mover um dispositivo para outro ambiente:

do {
  try await structure.move(device: light, to: room)
} catch let error as HomeError {
  // Code for handling the exception
}

Lista de APIs

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

API Descrição
devices() Conferir todos os dispositivos visíveis para esta conta.
device(id:) Receba um Publisher para um dispositivo especificado que emita o estado atual e novamente em atualizações futuras de estado.
structures() Receba todas as estruturas da Conta do Google. Retorna um Query<Structure> que oferece mais opções de recuperação e filtragem.
structure(id:) Receba a estrutura com o ID correspondente.
rooms() Receber todos os quartos na Conta do Google. Retorna um Query<strRoom> que oferece mais opções de recuperação e filtragem.
room(id:) Receba um Publisher para uma sala específica que emite o estado atual e novamente em atualizações de estado futuras.

O Structure tem as seguintes APIs:

API Descrição
deleteRoom(id:) Excluir uma sala com o ID dela.
id O ID exclusivo do sistema da estrutura.
move(device:, to:) Mover um dispositivo para outro ambiente na estrutura.
move(device:, to:) Move o dispositivo com o ID fornecido para a sala com o ID fornecido.
move(devices:, to:) Move os dispositivos para o ambiente especificado.
move(devices:, to:) Move os dispositivos com os IDs fornecidos para a sala com o ID fornecido.
name O nome da estrutura fornecido pelo usuário.

Room tem as seguintes APIs:

API Descrição
id O ID exclusivo do sistema do quarto.
name O nome da sala fornecido pelo usuário.
structureID O ID exclusivo do sistema da estrutura a que o quarto pertence.