Accedere ai dispositivi e ai metadati dei dispositivi per Android

È possibile accedere alle API dei dispositivi tramite le API Home per Android. 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 caratteristiche di dispositivi specifici con le API dei dispositivi, è necessario importarli singolarmente.

Ad esempio, per utilizzare la caratteristica On/Off Matter e il tipo di dispositivo Unità plug-in 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 dei dati su Android.

Gestione degli errori

Qualsiasi metodo nelle API Home può generare un'eccezione HomeException, pertanto ti consigliamo di utilizzare un blocco try-catch per rilevare 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 getSubErrorCodes() metodo e controlla il risultato.

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

Per ulteriori informazioni, consulta Gestione degli errori.

Per un esempio, consulta Invio di un comando a un dispositivo.

Chiamate di esempio

Recuperare un elenco di dispositivi

Una volta che hai un riferimento all'istanza Structure, una chiamata devices() restituisce un Flow di dispositivi accessibili dalla 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 puoi accedere agli stati di ogni dispositivo e inviare comandi ai dispositivi.

Con la release 1.8 delle API Home, hai la possibilità di fare in modo che l'API rappresenti ogni dispositivo multipart come un singolo dispositivo impostando il parametro enableMultipartDevices del metodo devices() su true. Per ulteriori informazioni, consulta Dispositivi multipart su Android.

Leggere lo stato di un dispositivo

Dai un'occhiata a un esempio di controllo dell'attributo OnOff dalla caratteristica On/Off del dispositivo. Utilizzando il modello dei dati delle caratteristiche delle API Home, in cui questa caratteristica è identificata come OnOff, puoi recuperare i dati delle caratteristiche 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()!!

Per saperne di più sulla funzione di flusso Kotlin, consulta distinctUntilChanged.

Invalidare lo stato in un abbonamento alle caratteristiche

L'interfaccia TraitStateInvalidation consente di invalidare uno stato recuperato tramite gli abbonamenti al dispositivo di destinazione nei casi in cui lo stato non viene segnalato correttamente. Esempi di casi in cui lo stato potrebbe non essere segnalato correttamente includono l'utilizzo di attributi nelle caratteristiche Matter con la qualità "C" o a causa di un'implementazione del dispositivo che causa inaspettatamente il problema.

Questa API esegue una lettura forzata dello stato attuale del trait e restituisce il risultato tramite i flussi di trait esistenti.

Recupera la caratteristica, quindi esegui un forceRead sulla caratteristica:

val onOffTrait = device.?type(DimmableLightDevice)?.map{it.trait(OnOff)}.first()
onOffTrait.forceRead()

Recuperare un elenco di caratteristiche del tipo di dispositivo

I tipi di dispositivi devono essere utilizzati come punto di ingresso per la lettura delle caratteristiche, in quanto decompongono un dispositivo nelle sue parti funzionali (come gli endpoint in Matter).

Tengono inoltre conto delle collisioni di caratteristiche nel caso in cui un dispositivo abbia due tipi di dispositivi, entrambi con la stessa caratteristica. Ad esempio, se un dispositivo è sia un altoparlante sia una luce dimmerabile, avrà due caratteristiche On/Off e due caratteristiche di controllo del livello.

Per recuperare 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 caratteristiche può verificarsi quando un dispositivo ha due caratteristiche con lo stesso nome. Ad esempio, onOff potrebbe fare riferimento a un'istanza della caratteristica OnOff standard oppure a un'istanza di una caratteristica OnOff definita dal produttore. Per eliminare qualsiasi potenziale ambiguità in merito alla caratteristica prevista, un'istanza Trait a cui si fa riferimento tramite un dispositivo deve essere preceduta da uno spazio dei nomi di qualificazione. 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 una caratteristica specifica del produttore, fai riferimento direttamente:

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

Recuperare un elenco di dispositivi con una caratteristica specifica

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

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

Per un elenco completo delle caratteristiche disponibili nelle API Home, consulta l'interfaccia Trait per un elenco completo di caratteristiche disponibili nelle API Home.

Recuperare un elenco di dispositivi con tipi di dispositivi simili

Per recuperare 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 principale. Ad esempio, non esiste un tipo di dispositivo "Luce". Esistono invece quattro tipi di dispositivi diversi che potrebbero rappresentare una luce, come mostrato nell'esempio precedente. Pertanto, per ottenere una visione completa del tipo di dispositivo di livello superiore in una casa, è necessario includere più tipi di dispositivi nei flussi filtrati.

Per un elenco completo dei tipi di dispositivi disponibili nelle API Home, consulta l'interfaccia DeviceType.

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

La caratteristica BasicInformation include informazioni come l'ID fornitore, l'ID prodotto, il nome del prodotto e il 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}")

Identificazione dei dispositivi da cloud a cloud per i produttori di dispositivi

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

  • L'ID fornitore rilasciato da Connectivity Standards Alliance (Alliance) "matterOriginalVendorId": "0xfff1",

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

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

Quando inserisci questi campi stringa, utilizza gli ID Matter fornitore e prodotto, se li hai. Se non sei un Alliance membro 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 di dispositivi e caratteristiche

I dispositivi e le caratteristiche delle API Home hanno metadati associati che possono aiutarti a gestire l'esperienza utente in un'app.

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

Recuperare 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 (ad esempio il controllo del dispositivo e le automazioni suggerite) per i loro dispositivi, è utile verificare qual è il tipo di dispositivo principale per un dispositivo.

Innanzitutto, recupera i tipi di dispositivo utilizzando type(), quindi determina i tipi principali:

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

Verificare se una caratteristica è online

Utilizza il metodo connectivityState() per controllare la connettività di una caratteristica:

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

Alcune caratteristiche, in genere le caratteristiche smart home di Google, potrebbero essere visualizzate offline se il dispositivo non ha connettività internet. Questo perché queste caratteristiche sono basate sul cloud e non hanno routing locale.

Controllare 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à di tutte le caratteristiche del dispositivo.

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

In caso di tipi di dispositivi misti, quando non è presente la connettività internet, potrebbe essere visualizzato lo stato PARTIALLY_ONLINE. Matter Le caratteristiche standard potrebbero essere ancora online a causa del routing locale, ma le caratteristiche basate sul cloud saranno offline.

Controllare il routing di rete di una caratteristica

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

Il valore di località sconosciuto UNSPECIFIED è possibile, ad esempio, durante l'avvio di un'app che 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. È il client a dover determinare 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à di tutte le caratteristiche del dispositivo.

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

Uno stato MIXED può essere osservato in uno scenario simile a quello della connettività PARTIALLY_ONLINE: alcune caratteristiche sono basate sul cloud, mentre altre sono locali.

Modificare il nome di un dispositivo

Chiama il setName() metodo per modificare il nome di un dispositivo:

mixerDevice.setName("Grendel")

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.