API Structure su Android

È possibile accedere alle API Structure tramite le API Home per Android. Importa questi pacchetti nella tua app:

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

Gestione degli errori

Qualsiasi metodo nelle API Home può generare un errore HomeException, pertanto ti consigliamo di utilizzare un blocco try-catch per intercettare HomeException in tutte le chiamate.

Quando gestisci HomeException, controlla i campi error.code e error.message per scoprire cosa è andato storto. Potrebbero essere presenti anche codici di errore secondari, quindi chiama il metodo getSubErrorCodes() e controlla il risultato.

Qualsiasi eccezione non gestita causerà l'arresto anomalo dell'app.

Per saperne di più, consulta Gestione degli errori.

Chiamate di esempio

Recuperare un elenco di strutture

Una volta inizializzata, una chiamata structures() restituisce un flusso di strutture accessibili:

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

L'API structures() è un flusso che potrebbe non restituire immediatamente un elenco valido di strutture. Se la tua app è reattiva e si iscrive a questo flusso per gestire la UI, alla fine dovrebbe essere restituito un elenco valido di strutture. Esistono altre situazioni in cui potrebbe essere restituito un elenco di strutture vuoto, ad esempio se lo smartphone dell'utente perde la connettività o se l'utente ha revocato le autorizzazioni alla tua app. Devi assicurarti di gestire questi casi nella tua app.

In alternativa, se è necessario utilizzare la programmazione imperativa anziché quella reattiva, è possibile utilizzare un operatore di flusso terminale:

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

Questa chiamata attende che un elenco valido di strutture venga inviato tramite il flusso e scade se l'elenco non viene ricevuto entro il timeout designato dall'app.

Recupero delle proprietà della struttura

Con l'elenco delle strutture a portata di mano, puoi accedere alle relative proprietà:

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

Trovare una struttura in base al nome

Se conosci il nome di una struttura, puoi accedervi anche utilizzando la proprietà name:

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

Da qui è possibile accedere a proprietà, stanze e dispositivi per ogni struttura.

Lavorare con più strutture

Per utilizzare più di una struttura, ottieni un riferimento separato per ciascuna:

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
}

Ottenere un elenco di stanze

Con una struttura a portata di mano, puoi ottenere un elenco di stanze e accedere alle relative proprietà:

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

Crea una stanza virtuale

Per creare una nuova stanza:

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

Eliminare una stanza

In alternativa, puoi eliminare una stanza:

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

Puoi anche eliminare una stanza solo con un ID:

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

Se viene eliminata una stanza con dispositivi, questi rimarranno nella struttura ma non saranno più assegnati a una stanza.

Spostare i dispositivi in un'altra stanza

Una volta creata una struttura, puoi spostare i dispositivi in un'altra stanza all'interno di quella struttura:

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

Se hai solo gli ID dispositivo e stanza, puoi anche spostare i dispositivi:

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

Modificare il nome di una stanza

Chiama il metodo setName() per modificare il nome di una stanza:

livingRoom.setName("Living Room")

I nomi verranno troncati se superano il limite di 60 punti di codice Unicode (caratteri) e non verranno generati errori. Gli sviluppatori sono responsabili della gestione dei nomi lunghi e, ad esempio, possono decidere se informare gli utenti che i nomi verranno troncati.

Nell'ecosistema Google Home, per la maggior parte dei tipi di dispositivi, gli utenti possono concedere le autorizzazioni per tutti i dispositivi di quel tipo contemporaneamente. Per i tipi di dispositivi sensibili o con limitazioni, come serrature, videocamere o campanelli, gli utenti devono concedere l'autorizzazione singolarmente.

Per determinare se un utente ha concesso l'autorizzazione per accedere a un tipo di dispositivo sensibile o con limitazioni, utilizza la funzione consentedDeviceTypes() a livello di struttura:

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

Automazioni

Il punto di accesso all'API Automation avviene tramite una struttura. Per saperne di più sulle automazioni nelle API Home, consulta la panoramica dell'API Automation su Android.