Accedere ai dispositivi e ai metadati dei dispositivi per iOS

È possibile accedere alle API di dispositivo tramite le API Home per iOS. Importa i seguenti pacchetti nella tua app:

import GoogleHomeSDK
import GoogleHomeTypes

Per ulteriori informazioni, consulta Modello dei dati su iOS.

Gestione degli errori

Alcuni metodi nelle API Home generano un HomeError, pertanto ti consigliamo di utilizzare un blocco do-catch per intercettare HomeError in queste chiamate.

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

Eventuali errori non gestiti causeranno l'arresto anomalo dell'app.

Per ulteriori informazioni, consulta Gestione degli errori.

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

Chiamate di esempio

Ottenere un elenco di dispositivi

Con un riferimento all'oggetto Home, invoca devices() per ottenere un Query di dispositivi accessibili. Chiama il metodo batched() di Query, che emette un Set che riflette lo stato corrente della casa a ogni modifica dei metadati del dispositivo. In alternativa, chiama Query.list() per avere un scatto dei dispositivi disponibili. Si tratta di un metodo di utilità che si iscrive allo stream batched() e restituisce il primo valore emesso. Query.stream() produce uno stream che emette nuovi valori in base alle modifiche dei metadati del dispositivo, come nome, stanza o struttura. All'interno, utilizza batched() ed emette solo le proprietà modificate.

// Get a list of all devices accessible to the user
let homeDevices = try await self.home.devices().list()

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

Ottenere i tipi di dispositivo

Per ottenere i tipi di dispositivi associati a un dispositivo, leggi la proprietà types del dispositivo, che restituisce un DeviceTypeController.

Chiama DeviceTypeController.subscribe(_:) per iscriverti agli aggiornamenti per un determinato tipo di dispositivo:

let devices = try await self.home.devices().list()
if let device = devices.first(where: { $0.id == myDeviceId }) {
  var receivedUpdate1 = false
  var receivedUpdate2 = false
  device.types.subscribe(OnOffLightDeviceType.self)
    .assertNoFailure()
    .sink { device in
      if !receivedUpdate1 {
        receivedUpdate1 = true
        Task {
          try await device.matterTraits.onOffTrait?.on()
        }
        return
      }
      if !receivedUpdate2 {
        receivedUpdate2 = true
        return
      }
      fatalError("Received unexpected update")
    }
}

Se il dispositivo non supporta il tipo specificato, viene restituito un Empty Publisher che si completa immediatamente.

Se il dispositivo supporta un tipo di dispositivo specifico, puoi ottenere un handle per quel tipo chiamando get():

if let device = devices.first(where: { $0.id == myDeviceId }) {
  let deviceType = await device.types.get(OnOffLightDeviceType.self)
}

Se il dispositivo non supporta il tipo specificato, viene restituito nil.

Chiama DeviceTypeController.subscribeAll() per ricevere un Publisher di DeviceTypeCollection. Questa classe ti consente di verificare se il dispositivo ha un determinato tipo:

if let device = devices.first(where: { $0.id == myDeviceId }) {
  device.types.subscribeAll()
    .assertNoFailure()
    .sink { types in
      let lightDeviceType = types[OnOffLightDeviceType.self]
      let fanDeviceType = types[FanDeviceType.self]
    }
}

Recupera una caratteristica del tipo di dispositivo

I tipi di dispositivi sono il punto di ingresso per la lettura delle caratteristiche, in quanto decompongono un dispositivo nei relativi 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 che una luce dimmerabile, avrà due attributi On/Off e due di controllo del livello.

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 che è inteso, fai riferimento a un tratto tramite una delle due raccolte di tratti su ogni tipo di dispositivo.

Per gli attributi standard, ovvero quelli analoghi ai Matter cluster standard, utilizza matterTraits. Ad esempio, per ottenere un tratto specifico per il tipo di dispositivo Luce dimmerabile:

if let dimmableLightDeviceType =
  await device.types.get(DimmableLightDeviceType.self)
{
  // Accessing standard trait on the type.
  let levelControlTrait =
    dimmableLightDeviceType.matterTraits.levelControlTrait.self
}

Per le caratteristiche di Google, utilizza googleTraits:

if let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) {
  // Accessing Google trait on the type.
  let doorbellPressTrait =
    doorbellDeviceType.googleTraits.doorbellPressTrait.self
}

Per accedere a un tratto specifico del produttore, fai riferimento tramite la proprietà traits, ma precedilo con il nome del pacchetto del produttore:

let deviceType = await device1?.types.get(OnOffLightDeviceType.self)
// Accessing custom trait on the type.
if let spinnerTrait = deviceType?.traits[ExampleOrganization.SpinnerTrait.self] {
  let rpmVal = spinnerTrait.attributes.rpm
}

Leggere lo stato di un dispositivo

Guarda questo esempio di controllo dell'attributo OnOff dal tratto On/Off del dispositivo:

let lightDevices = devices.filter {
  $0.types.contains(OnOffLightDeviceType.self)
}
let light1 = lightDevices.first
let lightDeviceTypeOptional = await light1?.types.get(OnOffLightDeviceType.self)
if let onOffTrait = lightDeviceTypeOptional?.matterTraits.onOffTrait {
  let onOffVal = onOffTrait.attributes.onOff
}

Ottenere un elenco di dispositivi con un tratto specifico

Per ottenere un elenco di dispositivi con un tratto specifico, devi eseguire un'iterazione su tutti i dispositivi, sui tipi di dispositivi di ciascun dispositivo e sui tratti di ciascun tipo di dispositivo. Ad esempio, per ottenere un elenco di dispositivi in casa che hanno tutti il tratto On/Off:

// Get all light devices that support levelControl
var levelControlDevices: [HomeDevice] = []
var allDevices = try await home.devices().list()
for device in allDevices {
  if let deviceType = await device.types.get(OnOffLightDeviceType.self) {
    if deviceType.traits.contains(Matter.LevelControlTrait.self) {
      levelControlDevices.append(device)
    }
  }
}

Consulta l'indice delle caratteristiche su iOS per un elenco completo delle caratteristiche 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)
let lightDevices =
  try await self.home.devices().list().compactMap {
    $0.types.contains(DimmableLightDeviceType.self)
      || $0.types.contains(OnOffLightDeviceType.self)
      || $0.types.contains(ColorTemperatureLightDeviceType.self)
      || $0.types.contains(ExtendedColorLightDeviceType.self)
  }

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 possono 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.

Consulta la sezione Tipi di dispositivi supportati su iOS per un elenco completo dei tipi di dispositivi e delle relative caratteristiche disponibili nelle API Home.

Ottenere il nome del fornitore, l'ID fornitore o l'ID prodotto di un dispositivo

L'attributo BasicInformationTrait include informazioni quali ID fornitore, ID prodotto, nome prodotto e numero di serie di un dispositivo:

guard
  let vendorName =
    basicInfoTrait.attributes.vendorName
else {
  fatalError("Failed to get vendorName")
}
guard
  let vendorID =
    basicInfoTrait.attributes.vendorID
else {
  fatalError("Failed to get vendorID")
}
guard
  let productID =
    basicInfoTrait.attributes.productID
else {
  fatalError("Failed to get 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 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, che viene creato 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 del 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à (routing locale o remoto) di un tratto.

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 se un tipo di dispositivo è il tipo principale del dispositivo.

if let deviceType =
  await device?.types.get(HumiditySensorDeviceType.self)
{
  if deviceType.metadata.isPrimaryType {
    print("Humidity Sensor is the primary type on this device.")
  } else {
    print("Humidity Sensor isn't the primary type on this device.")
  }
}

Controllare se un tratto è online

Leggi la proprietà connectivityState per controllare la connettività di un tratto:

let levelControlConnectivity =
  levelControlTrait.metadata.sourceConnectivity
  .connectivityState

Alcuni tratti, in genere quelli di Google smart home, potrebbero essere visualizzati offline se il dispositivo non ha una connessione a internet. Questo accade perché questi tratti sono basati su 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à per tutti i tratti del dispositivo.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

Uno stato partiallyOnline può essere osservato nel caso di tipi di dispositivi misti quando non è presente una connessione a internet. I tratti Matter standard potrebbero essere ancora online a causa del routing locale, ma quelli basati 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 (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 non avranno esito positivo le richieste di interazione da comandi o eventi. Spetta al cliente stabilire come gestire questi dispositivi.

let levelControlLocality =
  levelControlTrait.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.

let lightLocality =
  dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality

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

Modificare il nome di un dispositivo

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

let updatedDevice = try await theDevice.setName("new device name")

Quando cambi il nome di un dispositivo, la struct HomeDevice originale rimane invariata e la modifica viene applicata all'oggetto HomeDevice aggiornato restituito.

elenco delle API

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

API Descrizione
device(id:) Restituisce un Publisher per il dispositivo specificato che emette lo stato del dispositivo ogni volta che cambia.
devices() Ottieni tutti i dispositivi in tutte le strutture sull'Account Google. Restituisce un Query<HomeDevice> che fornisce ulteriori opzioni di recupero e filtro.

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

API Descrizione
id L'ID sistema univoco del dispositivo.
name Il nome del dispositivo fornito dall'utente.
structureID L'ID della struttura a cui è assegnato il dispositivo. Restituisce un String?.
roomID L'ID della camera a cui è assegnato il dispositivo. Restituisce un String?.
types Ottieni un tipo specifico o tutti i tipi disponibili sul dispositivo.
isMatterDevice Se il dispositivo è supportato da Matter.
sourceConnectivity La connettività di origine del dispositivo, che rappresenta gli stati di connettività aggregati e la località di rete delle caratteristiche del dispositivo.