Dostęp do urządzeń i metadanych urządzeń w iOS

Dostęp do interfejsów API urządzeń można uzyskać za pomocą interfejsów Home API na iOS. Zaimportuj do aplikacji te pakiety:

import GoogleHomeSDK
import GoogleHomeTypes

Więcej informacji znajdziesz w artykule Model danych na iOS.

Obsługa błędów

Niektóre metody w interfejsach Home API zgłaszają wyjątek HomeError, dlatego zalecamy użycie bloku do-catch, aby przechwycić wyjątek HomeError w przypadku tych wywołań.

Podczas obsługi HomeError sprawdź pola codemessage, aby dowiedzieć się, co poszło nie tak.

Wszelkie nieobsłużone błędy spowodują awarię aplikacji.

Więcej informacji znajdziesz w sekcji Obsługa błędów.

Przykład znajdziesz w artykule Wysyłanie polecenia do urządzenia.

Przykładowe połączenia

Pobieranie listy urządzeń

Odwołując się do obiektu Home, wywołaj devices(), aby uzyskać Query dostępnych urządzeń. Wywołaj metodę Query's batched(), która emituje zbiór odzwierciedlający bieżący stan domu przy każdej zmianie metadanych urządzenia. Możesz też zadzwonić pod numer Query.list(), aby uzyskać informacje o dostępnych urządzeniach. Jest to wygodna metoda, która subskrybuje strumień batched() i zwraca pierwszą wyemitowaną wartość. Query.stream() tworzy strumień, który emituje nowe wartości w przypadku zmian metadanych urządzenia, takich jak jego nazwa, pomieszczenie lub struktura. Wewnętrznie używa funkcji batched() i emituje tylko zmienione właściwości.

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

W tym miejscu możesz sprawdzić stan każdego urządzenia i wysyłać do niego obsługiwane polecenia.

Pobieranie typów urządzeń

Aby uzyskać typy urządzeń powiązane z urządzeniem, odczytaj właściwość types urządzenia, która zwraca DeviceTypeController.

Zadzwoń pod numer DeviceTypeController.subscribe(_:), aby subskrybować aktualizacje dotyczące określonego typu urządzenia:

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")
    }
}

Jeśli urządzenie nie obsługuje określonego typu, zwraca Empty Publisher, które natychmiast się kończy.

Jeśli urządzenie obsługuje określony typ, możesz uzyskać do niego dostęp, wywołując funkcję get():

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

Jeśli urządzenie nie obsługuje określonego typu, zwraca wartość nil.

Zadzwoń pod numer DeviceTypeController.subscribeAll(), aby otrzymać Publisher w wysokości DeviceTypeCollection. Ta klasa umożliwia sprawdzenie, czy urządzenie jest określonego typu:

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

Pobieranie cechy typu urządzenia

Typy urządzeń to punkt wejścia do odczytywania cech, ponieważ dzielą urządzenie na części funkcjonalne (np. punkty końcowe w Matter).

Uwzględniają one też kolizje cech w przypadku, gdy urządzenie ma 2 typy, z których oba mogą mieć tę samą cechę. Jeśli na przykład urządzenie jest zarówno głośnikiem, jak i ściemnianym oświetleniem, będzie miało 2 cechy włączania/wyłączania i 2 cechy sterowania poziomem.

Inny rodzaj kolizji cech może wystąpić, gdy urządzenie ma 2 cechy o tej samej nazwie. Na przykład onOff może odnosić się do instancji standardowego atrybutu OnOff lub do instancji atrybutu OnOff zdefiniowanego przez producenta. Aby uniknąć niejasności co do tego, która cecha jest zamierzona, odwołuj się do cechy za pomocą jednego z 2 zbiorów cech na każdym typie urządzenia.

W przypadku cech standardowych, czyli tych, które są analogiczne do klastrów standardowych, użyj matterTraits.Matter Na przykład, aby uzyskać konkretną cechę dla typu urządzenia Dimmable Light:

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

W przypadku atrybutów Google użyj googleTraits:

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

Aby uzyskać dostęp do cechy specyficznej dla producenta, odwołaj się do niej za pomocą traits właściwości, ale poprzedź ją nazwą pakietu producenta:

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
}

Odczytywanie stanu urządzenia

Spójrz na ten przykład sprawdzania atrybutu OnOff z cechy włączania/wyłączania urządzenia:

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
}

Pobieranie listy urządzeń o określonej cesze

Aby uzyskać listę urządzeń o określonej cesze, musisz przejść iteracyjnie przez urządzenia, typy urządzeń każdego urządzenia i cechy każdego typu urządzenia. Aby na przykład uzyskać listę urządzeń w domu, które mają cechę Włączanie/wyłączanie:

// 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)
    }
  }
}

Pełną listę cech dostępnych w interfejsach Home API znajdziesz w artykule Indeks cech w iOS.

Wyświetlanie listy urządzeń o podobnych typach

Aby uzyskać listę urządzeń reprezentujących wszystkie światła w domu:

// 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)
  }

W interfejsach Home API jest wiele typów urządzeń, które mogą reprezentować podstawowy typ urządzenia. Na przykład nie ma typu urządzenia „Światło”. Zamiast tego istnieją 4 różne typy urządzeń, które mogą reprezentować światło, jak pokazano w poprzednim przykładzie. Aby uzyskać pełny obraz urządzenia wyższego poziomu w domu, należy uwzględnić wiele typów urządzeń.

Pełną listę typów urządzeń i ich cech dostępnych w interfejsach Home API znajdziesz w sekcji Obsługiwane typy urządzeń w iOS.

Pobieranie nazwy dostawcy, identyfikatora dostawcy lub identyfikatora produktu w przypadku urządzenia

Cechy BasicInformationTrait zawierają informacje takie jak identyfikator dostawcy, identyfikator produktu, nazwa produktu i numer seryjny urządzenia:

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")
}

Identyfikacja urządzeń w chmurze dla producentów urządzeń

Jeśli jesteś producentem urządzeń i tworzysz Cloud-to-cloud urządzenia, aby identyfikować swoje Cloud-to-cloud urządzenia za pomocą cechy BasicInformation, możesz uwzględnić te pola tekstowe w odpowiedzi SYNC:

  • The Connectivity Standards Alliance (CSA) wydało identyfikator dostawcy:"matterOriginalVendorId": "0xfff1",

  • Identyfikator produktu, który jednoznacznie identyfikuje produkt sprzedawcy: "matterOriginalProductId": "0x1234",

  • unikalny identyfikator urządzenia, który jest tworzony w sposób określony przez producenta:"matterUniqueId": "matter-device-id",

Podczas wpisywania tych pól tekstowych użyj identyfikatorów Matterdostawcy i produktu, jeśli je masz. Jeśli nie jesteś członkiem CSA i nie masz przypisanych tych identyfikatorów, możesz pozostawić pola matterOriginalVendorIdmatterOriginalProductId puste, a jako identyfikator podać matterUniqueId.

W przykładowej odpowiedzi SYNC widać użycie tych pól:

{
  "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",
          }
        ]
      }
    ]
  }
}

Więcej informacji znajdziesz w Cloud-to-cloud SYNC dokumentacji.

Metadane urządzenia i cech

Urządzenia i cechy w interfejsach Home API mają powiązane z nimi metadane, które mogą ułatwiać zarządzanie wrażeniami użytkowników w aplikacji.

Każda cecha w interfejsach Home API zawiera właściwość sourceConnectivity z informacjami o stanie online i lokalizacji cechy (routing lokalny lub zdalny).

Pobieranie głównego typu urządzenia

Niektóre urządzenia mogą prezentować wiele typów urządzeń za pomocą interfejsów Home API. Aby mieć pewność, że użytkownicy widzą w aplikacji odpowiednie opcje (np. sterowanie urządzeniem i sugerowane automatyzacje) dla swoich urządzeń, warto sprawdzić, czy typ urządzenia jest jego typem podstawowym.

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.")
  }
}

Sprawdzanie, czy atrybut jest online

Odczytaj właściwość connectivityState, aby sprawdzić łączność cechy:

let levelControlConnectivity =
  levelControlTrait.metadata.sourceConnectivity
  .connectivityState

Niektóre cechy, zwykle cechy Google smart home, mogą być wyświetlane w trybie offline, jeśli urządzenie nie ma połączenia z internetem. Dzieje się tak, ponieważ te cechy są oparte na chmurze i nie mają routingu lokalnego.

Sprawdzanie połączenia urządzenia

Połączenie urządzenia jest sprawdzane na poziomie typu urządzenia, ponieważ niektóre urządzenia obsługują wiele typów. Zwracany stan jest kombinacją stanów łączności wszystkich cech na tym urządzeniu.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

Stan partiallyOnline może wystąpić w przypadku różnych typów urządzeń, gdy nie ma połączenia z internetem. Matter standardowe cechy mogą być nadal dostępne online ze względu na routing lokalny, ale cechy oparte na chmurze będą niedostępne.

Sprawdzanie routingu sieciowego cechy

Lokalizacja cechy jest też dostępna w interfejsach Home API. Ikona dataSourceLocality wskazuje, czy cecha jest przekazywana zdalnie (przez chmurę), lokalnie (przez lokalny hub) czy w trybie peer-to-peer (bezpośrednio z urządzenia na urządzenie, bez huba).

Nieznana wartość lokalizacji unspecified może wystąpić na przykład podczas uruchamiania aplikacji, która nie nawiązała jeszcze połączenia z hubem lub serwerem. Te urządzenia są niedostępne i nie będą odpowiadać na żądania interakcji z poleceń lub zdarzeń. To klient decyduje, jak obsługiwać takie urządzenia.

let levelControlLocality =
  levelControlTrait.metadata.sourceConnectivity
  .dataSourceLocality

Sprawdzanie routingu sieciowego urządzenia

Podobnie jak łączność, lokalizacja jest sprawdzana na poziomie typu urządzenia. Zwracany stan jest kombinacją lokalizacji wszystkich cech na tym urządzeniu.

let lightLocality =
  dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality

Stan mixed może wystąpić w podobnym scenariuszu jak stan łączności partiallyOnline: niektóre cechy są oparte na chmurze, a inne są lokalne.

Zmienianie nazwy urządzenia

Aby zmienić nazwę urządzenia, wywołaj metodę setName(_:):

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

Podczas zmiany nazwy urządzenia oryginalna struktura HomeDevice pozostaje bez zmian, a zmiana jest odzwierciedlana w zwracanym zaktualizowanym obiekcie HomeDevice.

Nazwy zostaną obcięte, jeśli przekroczą limit 60 punktów kodowych Unicode (znaków), i nie zostaną zgłoszone żadne błędy. Deweloperzy odpowiadają za obsługę długich nazw i mogą na przykład zdecydować, czy chcą informować użytkowników o tym, że nazwy będą skracane.

Lista interfejsów API

Po utworzeniu instancji Home można uzyskać dostęp do tych interfejsów API urządzenia:

Interfejs API Opis
device(id:) Zwraca Publisher dla określonego urządzenia, które emituje stan urządzenia za każdym razem, gdy się on zmienia.
devices() Uzyskaj dostęp do wszystkich urządzeń we wszystkich strukturach na koncie Google. Zwraca obiekt Query<HomeDevice>, który udostępnia dodatkowe opcje pobierania i filtrowania.

Gdy uzyskasz HomeDevice, możesz korzystać z tych interfejsów API:

Interfejs API Opis
id Unikalny identyfikator systemowy urządzenia.
name Nazwa urządzenia podana przez użytkownika.
structureID Identyfikator struktury, do której przypisane jest urządzenie. Zwraca wartość String?.
roomID Identyfikator pomieszczenia, do którego przypisane jest urządzenie. Zwraca wartość String?.
types Pobierz określony typ lub wszystkie typy dostępne na urządzeniu.
isMatterDevice Jeśli urządzenie jest objęte ochroną Matter.
sourceConnectivity Łączność źródłowa urządzenia, która reprezentuje zagregowane stany łączności i lokalizację sieciową cech urządzenia.