Accedere ai dispositivi e ai metadati dei dispositivi per iOS

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

import GoogleHomeSDK
import GoogleHomeTypes

Per saperne di più, consulta Modello dei dati su iOS.

Gestione degli errori

Alcuni metodi delle 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 saperne di più, consulta Gestione degli errori.

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

Chiamate di esempio

Recuperare un elenco di dispositivi

Con un riferimento all'Home oggetto, richiama devices() per ottenere una Query dei dispositivi accessibili. Chiama il Query's batched() metodo, che emette un set che riflette lo stato attuale di Home a ogni modifica dei metadati del dispositivo. In alternativa, chiama Query.list() per ottenere uno snapshot dei dispositivi disponibili. Si tratta di un metodo pratico che sottoscrive lo stream batched() e restituisce il primo valore emesso. Query.stream() produce uno stream che emette nuovi valori in caso di modifiche ai metadati del dispositivo, ad esempio il nome, la stanza o la struttura. Internamente, 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 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 saperne di più, consulta Dispositivi multipart su iOS.

Recuperare i tipi di dispositivo

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

Chiama DeviceTypeController.subscribe(_:) per abbonarti agli aggiornamenti di 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 di dispositivo specificato, restituisce un Empty Publisher che viene completato 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 _ = await device.types.get(OnOffLightDeviceType.self)
}

Se il dispositivo non supporta il tipo specificato, restituisce nil.

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

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

Recuperare una caratteristica del tipo di dispositivo

I tipi di dispositivo sono il 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 dispositivo, entrambi con la stessa caratteristica. Ad esempio, se un dispositivo è sia un vivavoce sia una luce dimmerabile, avrà due caratteristiche di accensione/spegnimento e due caratteristiche di controllo del livello.

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 standard OnOff oppure a un'istanza di una caratteristica OnOff definita dal produttore. Per eliminare qualsiasi potenziale ambiguità in merito alla caratteristica prevista, fai riferimento a una caratteristica tramite una delle due raccolte di caratteristiche su ogni tipo di dispositivo.

Per le caratteristiche standard, ovvero quelle analoghe ai Matter cluster standard, utilizza matterTraits. Ad esempio, per ottenere una caratteristica specifica 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.traits[Google.DoorbellPressTrait.self]
}

Per accedere a una caratteristica specifica del produttore, fai riferimento alla proprietà traits, ma anteponi 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

Dai un'occhiata a questo esempio di controllo dell'attributo OnOff della caratteristica di accensione/spegnimento 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
}

Recuperare un elenco di dispositivi con una caratteristica specifica

Per recuperare un elenco di dispositivi con un trait specifico, devi eseguire l'iterazione sui dispositivi, sui tipi di dispositivo di ogni dispositivo e sui trait di ogni tipo di dispositivo. Ad esempio, per recuperare un elenco di dispositivi in casa che hanno tutti la caratteristica di accensione/spegnimento:

// Get all light devices that support levelControl
var levelControlDevices: [HomeDevice] = []
let 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)
    }
  }
}

Per un elenco completo delle caratteristiche disponibili nelle API Home, consulta Indice delle caratteristiche su iOS.

Recuperare un elenco di dispositivi con tipi di dispositivo 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)
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 dispositivo che potrebbero rappresentare un tipo di dispositivo principale. Ad esempio, non esiste un tipo di dispositivo "Luce". Esistono invece quattro tipi di dispositivo 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 dispositivo.

Per un elenco completo dei tipi di dispositivo e delle relative caratteristiche disponibili nelle API Home, consulta Tipi di dispositivo supportati su iOS.

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

La BasicInformationTrait caratteristica include informazioni come l'ID fornitore, l'ID prodotto, il nome del prodotto e il 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 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 emesso 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 saperne di più, consulta la documentazione 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 include 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 dispositivo 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 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.")
  }
}

Verificare se una caratteristica è online

Leggi la proprietà connectivityState per controllare la connettività di una caratteristica:

let levelControlConnectivity =
  levelControlTrait.metadata.sourceConnectivity
  .connectivityState

Alcune caratteristiche, in genere le caratteristiche smart home di Google, potrebbero essere visualizzate offline se il dispositivo non ha una connessione a 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 dispositivo. Lo stato restituito è una combinazione degli stati di connettività di tutte le caratteristiche del dispositivo.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

In caso di tipi di dispositivo misti, quando non è presente una connessione a internet, potrebbe essere visualizzato lo stato partiallyOnline. Matter Le caratteristiche standard di Matter 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. È compito del client determinare 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à di tutte le caratteristiche del dispositivo.

let lightLocality =
  dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality

Uno stato mixed può essere osservato in uno scenario simile a quello della connettività partiallyOnline: 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:

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

Quando modifichi il nome di un dispositivo, la struttura HomeDevice originale rimane invariata e la modifica viene riportata nell'oggetto HomeDevice aggiornato restituito.

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.