È possibile accedere alle API Device 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 di dispositivi o tratti specifici con le API Device, devi importarli singolarmente.
Ad esempio, per utilizzare il tratto On/Off Matter e il tipo di dispositivo On/Off Plug-in Unit, importa i seguenti pacchetti nella tua applicazione:
import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffPluginUnitDevice
Per saperne di più, 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 su tutte le chiamate.
Quando gestisci HomeException, controlla i campi
error.code e
error.message per scoprire cosa non ha funzionato. Potrebbero esserci anche codici di errore secondari, quindi chiama il metodo
getSubErrorCodes() e controlla il risultato.
Eventuali eccezioni non gestite causeranno l'arresto anomalo dell'app.
Per saperne di più, consulta Gestione degli errori.
Per un esempio, consulta Invia un comando a un dispositivo.
Chiamate di esempio
Visualizza un elenco di dispositivi
Una volta ottenuto un riferimento all'istanza Structure, una chiamata devices()
restituisce un Flow 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, puoi accedere agli stati di ogni dispositivo e inviare comandi ai dispositivi.
Con la release 1.8 delle API Home, puoi fare in modo che l'API rappresenti ogni dispositivo multiparte come un singolo dispositivo impostando il parametro enableMultipartDevices del metodo devices() su true. Per saperne di più, consulta Dispositivi multiparte su Android.
Leggi lo stato di un dispositivo
Ecco 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 è identificato come OnOff, puoi recuperare i dati del tratto 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.
Annulla lo stato in una sottoscrizione di un tratto
L'interfaccia TraitStateInvalidation
offre la possibilità di invalidare uno stato recuperato tramite le sottoscrizioni
al dispositivo di destinazione nei casi in cui lo stato non venga segnalato correttamente.
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 l'implementazione di un dispositivo che causa il problema in modo imprevisto.
Questa API forza la lettura dello stato attuale del tratto e restituisce il risultato tramite i flussi del tratto esistenti.
Recupera il tratto, quindi esegui un forceRead sul tratto:
val onOffTrait = device.?type(DimmableLightDevice)?.map{it.trait(OnOff)}.first()
onOffTrait.forceRead()
Visualizza un elenco dei tratti dei tipi di dispositivo
I tipi di dispositivi devono essere utilizzati come punto di accesso per la lettura dei tratti, in quanto scompongono un dispositivo nelle sue parti funzionali (come gli endpoint in Matter).
Inoltre, tengono conto delle collisioni dei 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 tratti On/Off e due tratti Controllo livello.
Per ottenere l'elenco dei tratti 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 conflitto 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 standard OnOff o a un'istanza di un tratto OnOff definito dal produttore. Per eliminare qualsiasi potenziale ambiguità su quale tratto è previsto, un'istanza Trait a cui viene fatto riferimento tramite un dispositivo deve essere preceduta da uno spazio dei nomi di qualifica. Per i trait standard, ovvero quelli analoghi ai cluster standard Matter, utilizza standardTraits. Per i tratti
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)
Recupera 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 della casa che hanno tutti il tratto 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.
Ottieni un elenco di dispositivi con tipi di dispositivi simili
Per ottenere 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 esistono diversi tipi di dispositivi che potrebbero rappresentare un tipo di dispositivo principale. Ad esempio, non esiste un tipo di dispositivo "Luce". Esistono invece quattro diversi tipi di dispositivi che potrebbero rappresentare una luce, come mostrato nell'esempio precedente. Pertanto, per ottenere una visualizzazione 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.
Recupera l'ID fornitore o l'ID prodotto di un dispositivo
Il tratto 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 cloud-to-cloud per i produttori di dispositivi
Se sei un produttore di dispositivi e crei dispositivi Cloud-to-cloud,
per identificare i tuoi
dispositivi Cloud-to-cloud tramite il
tratto BasicInformation, puoi includere questi campi stringa nella
loro risposta SYNC:
L'ID fornitore emesso da Connectivity Standards Alliance (Alliance):
"matterOriginalVendorId": "0xfff1",Un ID 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 di stringa, utilizza gli ID fornitore e prodotto Matter, se li hai. Se non sei un membro di Alliance 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 saperne di più, consulta la documentazione di SYNC Cloud-to-cloud.
Metadati di dispositivi e caratteristiche
Ai dispositivi e ai tratti nelle API Home sono associati metadati che possono aiutare a 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).
Recupera 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 dei dispositivi e le automazioni suggerite) per i loro dispositivi, è utile verificare qual è il tipo di dispositivo principale.
Innanzitutto, ottieni i tipi di dispositivo utilizzando
type(),
quindi determina i tipi principali:
val types = device.types().first() val primaryTypes = types.filter { it.metadata.isPrimaryType }
Controlla se un tratto è online
Utilizza il metodo connectivityState() per verificare la connettività di un tratto:
val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState
Alcuni tratti, in genere quelli di Google smart home, potrebbero essere visualizzati offline se il dispositivo non dispone di connessione a internet. Questo perché questi tratti sono basati su cloud e non hanno il routing locale.
Controlla 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 trait di quel dispositivo.
val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState
In caso di tipi di dispositivi misti, quando non è presente una connessione a internet, potrebbe essere visualizzato lo stato PARTIALLY_ONLINE.
I tratti standard di Matter potrebbero essere ancora online grazie al routing locale, ma i tratti basati su cloud saranno offline.
Recupera l'indirizzo IP del dispositivo
Per trovare l'indirizzo IP del dispositivo, utilizza l'attributo networkInterfaces del tratto GeneralDiagnostics. Gli indirizzi vengono restituiti come array di byte, che puoi formattare in stringhe IPv4 o IPv6 standard:
val ipAddresses =
trait.networkInterfaces?.flatMap { networkInterface ->
(networkInterface.ipv4Addresses + networkInterface.ipv6Addresses).mapNotNull { bytes ->
try {
java.net.InetAddress.getByAddress(bytes).hostAddress
} catch (e: java.net.UnknownHostException) {
null
}
}
} ?: emptyList()
Controlla il routing di rete di un tratto
La località di un tratto è disponibile anche nelle API Home. dataSourceLocality indica se il tratto viene instradato da remoto (tramite il cloud), localmente (tramite un hub locale) o 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
che non ha ancora raggiunto un hub o un server per la connettività del dispositivo. Questi dispositivi non sono raggiungibili e non riusciranno a soddisfare le richieste di interazione provenienti da comandi o eventi. Spetta al client determinare come gestire questi dispositivi.
val onOffLocality = onOffTrait?.metadata?.sourceConnectivity?.dataSourceLocality
Controlla il routing di rete per 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 di quel dispositivo.
val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality
Uno stato di MIXED può essere osservato in uno scenario simile
a quello della connettività PARTIALLY_ONLINE: alcuni tratti sono basati su cloud, mentre
altri sono locali.
Modifica il nome di un dispositivo
Chiama il metodo setName() 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.
Controlla l'appartenenza a un gruppo per un dispositivo
Un dispositivo fisico può appartenere a uno o più gruppi di dispositivi. Per vedere a quali gruppi appartiene un dispositivo, controlla il tratto GroupMembership sul dispositivo:
val groupIds = device.trait(GroupMembershipTrait)?.groupObjectIds.orEmpty()
for (groupId in groupIds) {
println("HomeAPI", "Device belongs to group: $groupId")
}
Al contrario, puoi osservare tutti i dispositivi membri appartenenti a un
DeviceGroup chiamando il
flusso devices() su un DeviceGroup:
group.devices(enableMultipartDevices = true).collect { members ->
println("HomeAPI", "Group contains ${members.size} devices")
}
Per ispezionare i tipi di dispositivi supportati da un DeviceGroup e inviare comandi al gruppo come singola entità, consulta Controlla un gruppo di dispositivi.