Estruturar APIs no Android

As APIs Structure podem ser acessadas pelas APIs Home para Android. Importe estes pacotes para seu app:

import com.google.home.Home
import com.google.home.Id
import com.google.home.Structure

Tratamento de erros

Qualquer método nas APIs Home pode gerar uma HomeException. Por isso, recomendamos que você use um try-catch para detectar HomeException em todas as chamadas.

Ao processar HomeException, verifique os campos error.code e error.message para saber o que deu errado. Também pode haver códigos de suberro também. Portanto, chame o método getSubErrorCodes() e verifique o resultado.

Qualquer exceção não tratada vai resultar em falha do app.

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

Exemplos de chamadas

Receber uma lista de estruturas

Depois de inicializada, uma chamada structures() retorna um fluxo de estruturas acessíveis a você:

// Get a flow of all structures accessible to the user
val allStructuresFlow: HomeObjectsFlow<Structure> = home.structures()

// Calling list() on a HomeObjectsFlow returns the first Set of elements.
val allStructures: Set<Structure> = allStructuresFlow.list()

A API structures() é um fluxo que pode não retornar imediatamente uma lista válida de estruturas. Se o app for reativo e assinar esse fluxo para controlar a interface, uma lista válida de estruturas será retornada. Há outras situações em que uma lista de estruturas 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 seu app. É importante processar esses casos no seu app.

Como alternativa, se a programação imperativa for estritamente necessária em vez da reativa, um operador de fluxo de terminal poderá ser usado:

val everyStructure = withTimeout(5000) { home.structures().first { it.isNotEmpty() } }

Essa chamada aguarda uma lista válida de estruturas passar pelo fluxo e expira se a lista não for recebida dentro de um tempo limite designado pelo app.

Receber propriedades da estrutura

Com a lista de estruturas em mãos, você pode acessar as propriedades delas:

// Get a flow on a structure. Flow emits new values on structure metadata changes: name.
val structureFlow: Flow<Structure> = home.structures().itemFlow(myStructureId)

// Get a snapshot of the structure.
val structure: Structure = structureFlow.first()

// Get structure properties
println("id ${structure.id}")
println("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:

val myHome = home.structures().list().first { it.name == "My home" }

A partir daí, as propriedades, os ambientes e os dispositivos de cada estrutura ficam acessíveis.

Trabalhar com várias estruturas

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

var structure1: Structure? = null
var structure2: Structure? = null

try {
  structure1 = home.structures().list().firstOrNull { it.name == "Main House" }
} catch (e: HomeException) {
  // Code for handling the exception
}
try {
  structure2 = home.structures().list().firstOrNull { it.name == "Guest Cottage" }
} catch (e: HomeException) {
  // Code for handling the exception
}

Receber uma lista de ambientes

Com uma estrutura em mãos, você pode receber uma lista de ambientes e acessar as propriedades deles:

val allRoomsFlow: HomeObjectsFlow<Room> = structure.rooms()
val allRooms: Set<Room> = allRoomsFlow.list()
val room: Room = allRooms.first()

println("id ${room.id}")
println("name ${room.name}")

Criar um ambiente

Para criar um novo ambiente:

val testName = "Test Room Name"
val newRoom: Room = structure.createRoom(testName)

Excluir um ambiente

Ou, como alternativa, você pode excluir um ambiente:

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

Também é possível excluir um ambiente apenas com um ID:

val roomToDelete1 = allRooms.filter { it.id == testRoomId }.firstOrNull()
structure.deleteRoom(roomToDelete1!!)

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

Mover dispositivos para outro ambiente

Depois de ter uma estrutura, você pode mover dispositivos para outro ambiente dentro dela:

val room2 = structure.rooms().get(Id("room_id_other_structure"))
    val device1 = structure.devices().get(Id("device_id1"))
    structure.moveDevicesToRoom(room2!!, listOf(device1!!))

Se você tiver apenas IDs de dispositivo e ambiente, também poderá mover dispositivos:

structure.moveDevicesToRoom(Id("room_id_other_structure"), listOf(Id("device_id1")))

Mudar o nome de um ambiente

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

livingRoom.setName("Living Room")

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.

No ecossistema do Google Home, para a maioria dos tipos de dispositivo, os usuários podem conceder permissões para todos os dispositivos desse tipo de uma só vez. Para tipos de dispositivo sensíveis ou restritos, como fechaduras, câmeras ou campainhas, os usuários precisam conceder permissão individualmente.

Para determinar se um usuário concedeu permissão para acessar um tipo de dispositivo sensível ou restrito, use a função consentedDeviceTypes() no nível da estrutura:

import com.google.home.Structure
import com.google.home.DeviceType
import com.google.home.DeviceTypeFactory
import com.google.home.consentedDeviceTypes // Extension function from the SDK
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

/**
 * Example of how an app may monitor which device types have been granted access by a user.
 */
fun monitorDeviceConsent(structure: Structure, myScope: CoroutineScope) {
    // Obtain the flow of consented device type factories
    val consentedTypesFlow: Flow<Set<DeviceTypeFactory<out DeviceType>>> =
        structure.consentedDeviceTypes()

    myScope.launch {
        consentedTypesFlow.collect { consentedSet ->
            // Check if the user has consented to share a specific restricted
            // type, such as a Doorbell or Camera.
            val hasCameraAccess = consentedSet.any {
                it.toString() == "matter.google.type.GoogleDoorbellDevice"
            }

            if (hasCameraAccess) {
                // Enable features that require camera access
            } else {
                // Inform the user or disable camera-specific features
            }
        }
    }
}

Automações

O ponto de entrada para a API Automation é uma estrutura. Para saber mais sobre automações nas APIs Home, consulte Visão geral da API Automation no Android.