Accedere ai dispositivi e ai relativi metadati

È possibile accedere alle API di dispositivo tramite le API Home. Importa questi pacchetti nella tua app:

import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id

Per utilizzare tipi o tratti di dispositivi specifici con le API Device, devono essere importati singolarmente.

Ad esempio, per utilizzare il tratto Matter On/Off e il tipo di dispositivo Plug-in Unit On/Off, importa i seguenti pacchetti nella tua applicazione:

import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffPluginUnitDevice

Per ulteriori informazioni, consulta Modello di dati.

Gestione degli errori

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

Quando gestisci HomeException, controlla i campi code e message per scoprire cosa è andato storto.

Eventuali eccezioni non gestite causeranno l'arresto anomalo dell'app.

Per ulteriori informazioni, consulta la sezione Gestione degli errori.

Per un esempio, consulta Inviare un comando a un dispositivo.

Chiamate di esempio

Visualizzare un elenco di dispositivi

Con la struttura disponibile, una chiamata devices() restituisce un flusso di dispositivi accessibili da quella struttura:

// Get a flow of all devices accessible to the user
val allDevicesFlow: HomeObjectsFlow<HomeDevice> = home.devices()

// Calling list() on a HomeObjectsFlow returns the first Set of elements.
val allDevices: Set<HomeDevice> = allDevicesFlow.list()

Da qui, sono accessibili gli stati di ciascun dispositivo e i comandi supportati possono essere inviati al dispositivo.

Leggere lo stato di un dispositivo

Vediamo un esempio di controllo dell'attributo OnOff dal tratto On/Off del dispositivo. Utilizzando il modello di dati dei tratti delle API Home, in cui questo tratto è identificate come OnOff, puoi recuperare i dati dei tratti tramite la classe standardTraits del tipo di dispositivo:

// Assuming we have a device.
val deviceFlow = home.devices().itemFlow(myDeviceId)

val device = deviceFlow.first()

// Get a flow of a standard trait on the type. distinctUntilChanged() is needed to only trigger
// on the specific trait changes and not the whole type.
val onOffTraitFlow: Flow<OnOff?> =
  device.type(DimmableLightDevice).map { it.standardTraits.onOff }.distinctUntilChanged()

val onOffTrait: OnOff = onOffTraitFlow.first()!!

Consulta distinctUntilChanged per scoprire di più sulla funzione di flusso di Kotlin.

Annullare lo stato in una sottoscrizione del tratto

L'interfaccia TraitStateInvalidation consente di invalidare uno stato recuperato tramite le iscrizioni al dispositivo di destinazione nei casi in cui lo stato non venga registrato correttamente. Alcuni esempi di casi in cui lo stato potrebbe non essere segnalato correttamente includono l'utilizzo di attributi nei tratti Matter con la qualità "C" o a causa di un'implementazione del dispositivo che causa il problema in modo imprevisto.

Questa API esegue una lettura forzata dello stato corrente dell'attributo e restituisce il risultato tramite i flussi di attributi esistenti.

Recupera il tratto, quindi esegui un forceRead sul tratto:

val generalDiagnosticsTrait = device.trait(GeneralDiagnostics).first()
generalDiagnosticsTrait.forceRead()

Visualizzare un elenco di tratti del tipo di dispositivo

I tipi di dispositivi devono essere utilizzati come punto di contatto per la lettura delle caratteristiche, in quanto scompongono un dispositivo nei suoi componenti funzionali (ad esempio gli endpoint in Matter).

Prendono inoltre in considerazione le collisioni di tratti nel caso in cui un dispositivo presenti due tipi di dispositivi, entrambi con lo stesso tratto. Ad esempio, se un dispositivo è sia uno speaker sia una luce dimmerabile, avrà due attributi On/Off e due di controllo del livello.

Per ottenere l'elenco delle caratteristiche disponibili per il tipo di dispositivo Luce dimmerabile:

// Get all types available on this device. Requires the types to be part of the registry during
// SDK initialization.
val typesFlow: Flow<Set<DeviceType>> = device.types()

// Get a snapshot of all types.
val types: Set<DeviceType> = typesFlow.first()

// Get the DimmableLightDevice instance from the set of types.
val dimmableLightDevice = types.filterIsInstance<DimmableLightDevice>().firstOrNull()

// Get all traits in the type + traits registered
val allTraits: Set<Trait> = dimmableLightDevice!!.traits()

Un altro tipo di collisione di tratti può verificarsi quando un dispositivo ha due tratti con lo stesso nome. Ad esempio, onOff potrebbe fare riferimento a un'istanza del tratto OnOff standard o a un'istanza di un tratto OnOff definito dal produttore. Per eliminare qualsiasi potenziale ambiguità sul tratto inteso, un'istanza Trait a cui viene fatto riferimento tramite un dispositivo deve essere preceduta da uno spazio dei nomi qualificante. Per le caratteristiche standard, ovvero quelle analoghe ai Matter cluster standard, utilizza standardTraits. Per le caratteristiche di Google, utilizza googleTraits:

// Accessing standard traits on the type.
val onOffTrait: OnOff? = dimmableLightDevice.standardTraits.onOff
val levelControlTrait: LevelControl? = dimmableLightDevice.standardTraits.levelControl

Per accedere a un tratto specifico del produttore, fai riferimento direttamente a questo:

// Accessing a custom trait on the type.
val customTrait = dimmableLightDevice.trait(MyCustomTrait)

Ottenere un elenco di dispositivi con un tratto specifico

La funzione filter in Kotlin può essere utilizzata per perfezionare ulteriormente le chiamate API. Ad esempio, per ottenere un elenco di dispositivi in casa che hanno tutti l'attributo On/Off:

// Get all devices that support OnOff
val onOffDevices: Flow<List<HomeDevice>> =
  home.devices().map { devices -> devices.filter { it.has(OnOff) } }

Consulta l'interfaccia Trait per un elenco completo dei tratti disponibili nelle API Home.

Visualizzare un elenco di dispositivi con tipi di dispositivi simili

Per visualizzare un elenco di dispositivi che rappresentano tutte le luci di una casa:

// Get a list of devices with similar device types (lights)
val lightDevices =
  home.devices().map { devices ->
    devices.filter {
      it.has(DimmableLightDevice) ||
        it.has(OnOffLightDevice) ||
        it.has(ColorTemperatureLightDevice) ||
        it.has(ExtendedColorLightDevice)
    }
  }

Nelle API Home sono presenti più tipi di dispositivi che potrebbero rappresentare un tipo di dispositivo di base. Ad esempio, non esiste il tipo di dispositivo "Luce". Esistono invece quattro diversi tipi di dispositivi che potrebbero rappresentare una luce, come mostrato nell'esempio precedente. Di conseguenza, per ottenere una visione completa del tipo di dispositivo di livello superiore in una casa, è necessario includere più tipi di dispositivi nei flussi filtrati.

Consulta l'interfaccia DeviceType per un elenco completo dei tipi di dispositivi disponibili nelle API Home.

Recuperare l'ID fornitore o l'ID prodotto di un dispositivo

La caratteristica BasicInformation include informazioni come ID fornitore, ID prodotto, nome prodotto e numero di serie di un dispositivo:

// Get device basic information. All general information traits are on the RootNodeDevice type.
val basicInformation = device.type(RootNodeDevice).first().standardTraits.basicInformation!!
println("vendorName ${basicInformation.vendorName}")
println("vendorId ${basicInformation.vendorId}")
println("productId ${basicInformation.productId}")

Identificare i dispositivi cloud-to-cloud

Se sei un produttore di dispositivi e crei dispositivi Cloud-to-cloud, per identificare i tuoi dispositivi Cloud-to-cloud tramite l'attributo BasicInformation, puoi includere questi campi di stringa nella risposta SYNC:

  • L'ID fornitore è stato emesso da Connectivity Standards Alliance (CSA): "matterOriginalVendorId": "0xfff1",

  • Un identificatore prodotto che identifica in modo univoco un prodotto di un fornitore: "matterOriginalProductId": "0x1234",

  • Un identificatore univoco del dispositivo, creato in modo specifico per il produttore: "matterUniqueId": "matter-device-id",

Quando inserisci questi campi di stringa, utilizza gli Matter ID fornitore e prodotto se li hai. Se non sei un membro del programma CSA e non ti sono stati assegnati questi ID, puoi lasciare vuoti i campi matterOriginalVendorId e matterOriginalProductId e fornire matterUniqueId come identificatore.

La risposta SYNC di esempio mostra l'utilizzo di questi campi:

{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "agentUserId": "1836.15267389",
    "devices": [
      {
        "id": "456",
        "type": "action.devices.types.LIGHT",
        "traits": [
          "action.devices.traits.OnOff",
          "action.devices.traits.Brightness",
          "action.devices.traits.ColorSetting",
        ],
        "willReportState": true,
        "deviceInfo": { ... },
        "matterOriginalVendorId": "0xfff1",
        "matterOriginalProductId": "0x1234",
        "matterUniqueId": "matter-device-id",
        "otherDeviceIds": [
          {
            "deviceId": "local-device-id",
          }
        ]
      }
    ]
  }
}

Per ulteriori informazioni, consulta la documentazione di Cloud-to-cloud SYNC.

Metadati del dispositivo e delle caratteristiche

I dispositivi e le caratteristiche nelle API Home hanno metadati associati, che possono essere utili per gestire l'esperienza utente in un'app.

Ogni tratto nelle API Home contiene una proprietà sourceConnectivity che contiene informazioni sullo stato online e sulla località di un tratto (routing locale o remoto).

Ottenere il tipo principale di un dispositivo

Alcuni dispositivi potrebbero presentare più tipi di dispositivi tramite le API Home. Per assicurarti che agli utenti vengano presentate le opzioni appropriate in un'app (come il controllo del dispositivo e le automazioni suggerite) per i loro dispositivi, è utile verificare qual è il tipo di dispositivo principale per un dispositivo.

Innanzitutto, ottieni i tipi di dispositivo utilizzando type(), poi determina quale sia il tipo principale:

val types = device.types().first()
val primaryType = types.first { it.metadata.isPrimaryType }

Controllare se un tratto è online

Utilizza il metodo connectivityState() per controllare la connettività di un tratto:

val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState

Alcuni tratti, in genere quelli di Google smart home, potrebbero essere visualizzati come offline se il dispositivo non ha una connessione a internet. Questo accade perché questi tratti sono basati su cloud e non hanno routing locale.

Verificare la connettività di un dispositivo

La connettività di un dispositivo viene effettivamente controllata a livello di tipo di dispositivo perché alcuni dispositivi supportano più tipi di dispositivi. Lo stato restituito è una combinazione degli stati di connettività per tutti i tratti del dispositivo.

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

Lo stato PARTIALLY_ONLINE può essere osservato nel caso di tipi di dispositivi misti quando non è presente una connessione a internet. Le caratteristiche standard di Matter potrebbero essere ancora online a causa del routing locale, ma quelle basate sul cloud saranno offline.

Controllare il routing di rete di un tratto

La località di un tratto è disponibile anche nelle API Home. dataSourceLocality indica se l'attributo viene indirizzato da remoto (tramite il cloud), localmente (tramite un hub locale) o in peer-to-peer (direttamente da dispositivo a dispositivo, senza hub).

Il valore di località sconosciuta UNSPECIFIED è possibile, ad esempio, durante l'avvio di un'app e non ha ancora raggiunto un hub o un server per la connettività del dispositivo. Questi dispositivi non sono raggiungibili e le richieste di interazione da comandi o eventi non andranno a buon fine. Spetta al cliente decidere come gestire questi dispositivi.

val onOffLocality = onOffTrait?.metadata?.sourceConnectivity?.dataSourceLocality

Controllare il routing di rete di un dispositivo

Come la connettività, la località viene controllata a livello di tipo di dispositivo. Lo stato restituito è una combinazione della località per tutti i tratti del dispositivo.

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

Uno stato MIXED può essere osservato in uno scenario simile a quello della connettività PARTIALLY_ONLINE: alcuni tratti sono basati su cloud, mentre altri sono locali.

elenco delle API

Una volta creata un'istanza di Home, tramite questa sono accessibili le seguenti API Device:

API Descrizione
devices() Ottieni tutti i dispositivi in tutte le strutture sull'Account Google. Restituisce un HomeObjectsFlow che fornisce ulteriori opzioni di recupero e filtro.

Una volta ottenuto un HomeDevice, tramite questo token puoi accedere alle seguenti API:

API Descrizione
allCandidates() Restituisce tutti i candidati all'automazione per il dispositivo e i relativi dispositivi secondari.
candidates() Restituisce tutti i candidati all'automazione per il dispositivo.
connectivityStateChanged L'ora più recente in cui è cambiato lo stato del dispositivo.
events(event) Recupera un flusso di un evento specifico.
events(trait) Recupera un flusso di tutti gli eventi per questo tratto.
events(traits) Recupera un flusso di tutti gli eventi in base a questi tratti.
getSourceConnectivity(trait) Ottieni i metadati per un determinato tratto. Restituisce un SourceConnectivity.
has(trait) Controlla se la caratteristica attualmente richiesta è supportata dal dispositivo.
has(type) Se il dispositivo supporta il tipo specificato.
id L'ID di sistema univoco del dispositivo.
isInRoom Se il dispositivo si trova in una stanza.
isInStructure Se il dispositivo si trova in una struttura.
isMatterDevice Se il dispositivo è supportato da Matter.
name Il nome del dispositivo fornito dall'utente.
room() La stanza a cui è assegnato il dispositivo. Restituisce un Room.
roomId L'ID della camera a cui è assegnato il dispositivo. Restituisce un Id.
sourceConnectivity La connettività di origine del dispositivo, che rappresenta gli stati di connettività aggregati e la località di rete delle caratteristiche del dispositivo.
structure() La struttura a cui è assegnato il dispositivo. Restituisce un Structure.
structureId L'ID della struttura a cui è assegnato il dispositivo. Restituisce un Id.
type(type) Ottieni la definizione del tipo con i tratti compilati (se disponibili) per l'accesso diretto. Restituisce sempre uno snapshot aggiornato dei tratti.
types() Visualizza un elenco di tutti i tipi disponibili sul dispositivo.