Dostęp do interfejsów API urządzeń można uzyskać za pomocą interfejsów API Google Home 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 API Google Home wywołują błąd HomeError, dlatego zalecamy użycie bloku do-catch, aby przechwycić błąd HomeError w tych wywołaniach.
Podczas obsługi błędu HomeError sprawdź pola code i message, aby dowiedzieć się, co poszło nie tak.
Wszelkie nieobsługiwane błędy spowodują awarię aplikacji.
Więcej informacji znajdziesz w artykule na temat obsługi błędów.
Przykład znajdziesz w sekcji Wysyłanie polecenia do urządzenia.
Przykładowe rozmowy
Pobieranie listy urządzeń
Korzystając z odwołania do obiektu Home, wywołaj devices(), aby uzyskać Query dostępnych urządzeń.
Wywołaj metodę batched() obiektu Query, która przy każdej zmianie metadanych urządzenia emituje zbiór odzwierciedlający bieżący stan domu. 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 po zmianie metadanych urządzenia, takich jak nazwa, pomieszczenie lub struktura. Wewnętrznie używa to 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()
Możesz tam uzyskać dostęp do stanów poszczególnych urządzeń i wysyłać do nich polecenia.
W wersji 1.8 interfejsów API Google Home możesz ustawić parametr enableMultipartDevices metody devices() na true, aby interfejs API reprezentował każde urządzenie wieloczęściowe jako jedno urządzenie. Więcej informacji znajdziesz w artykule Urządzenia wieloczęściowe na iOS.
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.
Wywołaj DeviceTypeController.subscribe(_:), aby zasubskrybować aktualizacje dla 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óry natychmiast się kończy.
Jeśli urządzenie obsługuje określony typ urządzenia, możesz uzyskać uchwyt do tego typu, wywołując funkcję get():
if let device = devices.first(where: { $0.id == myDeviceId }) { let _ = await device.types.get(OnOffLightDeviceType.self) }
Jeśli urządzenie nie obsługuje określonego typu, zwracana jest wartość nil.
Zadzwoń pod numer DeviceTypeController.subscribeAll(), aby uzyskać Publisher w wysokości DeviceTypeCollection.
Ta klasa pozwala sprawdzić, 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ń są punktem wejścia do odczytywania cech, ponieważ rozkładają urządzenie na elementy funkcjonalne (takie jak punkty końcowe w Matter).
Uwzględniają też kolizje cech w przypadku, gdy urządzenie ma 2 typy, które mogą mieć tę samą cechę. Jeśli na przykład urządzenie jest zarówno głośnikiem, jak i lampą z możliwością ściemniania, będzie miało 2 cechy On/Off i 2 cechy Level Control.
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 standardowej cechy OnOff lub do instancji cechy OnOff zdefiniowanej przez producenta. Aby wyeliminować wszelkie potencjalne niejasności co do tego, o którą cechę chodzi, odwołaj się do cechy za pomocą jednej z 2 kolekcji cech na każdym typie urządzenia.
W przypadku cech standardowych, czyli takich, które są analogiczne do klastrów standardowych Matter, użyj matterTraits. Aby na przykład uzyskać konkretną cechę typu urządzenia Ściemnialna lampa:
if let dimmableLightDeviceType = await device.types.get(DimmableLightDeviceType.self) { // Accessing standard trait on the type. let levelControlTrait = dimmableLightDeviceType.matterTraits.levelControlTrait.self }
W przypadku cech Google użyj: googleTraits:
if let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) { // Accessing Google trait on the type. let doorbellPressTrait = doorbellDeviceType.traits[Google.DoorbellPressTrait.self] }
Aby uzyskać dostęp do cechy specyficznej dla producenta, odwołaj się do niej za pomocą właściwości traits, 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 urządzenia Wł./wył.:
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ń z określoną cechą
Aby uzyskać listę urządzeń, które mają określoną cechę, musisz przejść przez urządzenia, typy urządzeń i cechy poszczególnych typów urządzeń. Aby na przykład uzyskać listę urządzeń w domu, które mają cechę Wł./wył.:
// 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) } } }
Pełną listę cech dostępnych w interfejsach API Google Home znajdziesz w indeksie cech na iOS.
Pobieranie listy urządzeń o podobnych typach
Aby uzyskać listę urządzeń, które reprezentują 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 API Google Home jest kilka 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ądzeń 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 API Google Home znajdziesz w artykule Obsługiwane typy urządzeń na iOS.
Uzyskiwanie nazwy dostawcy, identyfikatora dostawcy lub identyfikatora produktu dla urządzenia
Atrybut BasicInformationTrait zawiera 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ń połączonych z chmurą dla producentów urządzeń
Jeśli jesteś producentem urządzeń i tworzysz urządzenia Cloud-to-cloud, aby zidentyfikować urządzenia Cloud-to-cloud za pomocą cechy BasicInformation, możesz uwzględnić te pola ciągu znaków w odpowiedzi SYNC:
Identyfikator dostawcy wydany przez Connectivity Standards Alliance (Alliance):
"matterOriginalVendorId": "0xfff1",Identyfikator produktu, który jednoznacznie identyfikuje produkt dostawcy:
"matterOriginalProductId": "0x1234",Unikalny identyfikator urządzenia, który jest tworzony w sposób określony przez producenta:
"matterUniqueId": "matter-device-id",
Wpisując te pola tekstowe, użyj identyfikatorów dostawcy i produktu Matter, jeśli je masz. Jeśli nie jesteś członkiem Alliance i nie masz przypisanych tych identyfikatorów, możesz pozostawić pola matterOriginalVendorId i matterOriginalProductId puste i podać matterUniqueId jako identyfikator.
Przykładowa odpowiedź SYNC pokazuje 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 dokumentacji Cloud-to-cloud SYNC.
Metadane urządzenia i cechy
Urządzenia i cechy w interfejsach API Google Home mają powiązane metadane, które mogą pomóc w zarządzaniu wrażeniami użytkownika w aplikacji.
Każda cecha w interfejsach API Google Home zawiera właściwość sourceConnectivity, która zawiera informacje o stanie online cechy i jej lokalizacji (routing lokalny lub zdalny).
Pobieranie głównego typu urządzenia
Niektóre urządzenia mogą udostępniać wiele typów urządzeń za pomocą interfejsów API Google Home. Aby mieć pewność, że użytkownicy zobaczą w aplikacji odpowiednie opcje (takie jak sterowanie urządzeniem i sugerowane automatyzacje) dla swoich urządzeń, warto sprawdzić, czy dany typ urządzenia jest jego głównym typem.
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 cecha jest online
Aby sprawdzić połączenie cechy, odczytaj właściwość connectivityState:
let levelControlConnectivity = levelControlTrait.metadata.sourceConnectivity .connectivityState
Niektóre cechy, zwykle cechy Google smart home, mogą być wyświetlane jako offline, jeśli urządzenie nie ma połączenia z internetem. Dzieje się tak, ponieważ te cechy są działające w 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 urządzeń. Zwracany stan jest kombinacją stanów połączenia wszystkich cech na tym urządzeniu.
let lightConnectivity = dimmableLightDeviceType.metadata.sourceConnectivity .connectivityState
W przypadku różnych typów urządzeń, gdy nie ma połączenia z internetem, może być widoczny stan partiallyOnline. Niektóre standardowe cechy Matter mogą nadal być dostępne online dzięki lokalnemu routingowi, ale cechy działające w chmurze będą offline.
Uzyskiwanie adresu IP urządzenia
Aby znaleźć adres IP urządzenia, użyj atrybutu networkInterfaces zasobu GeneralDiagnosticsTrait.
Adresy są zwracane jako obiekty Data, które można sformatować jako standardowe ciągi IPv4 lub IPv6 za pomocą platformy Network:
func getIpAddresses(trait: Matter.GeneralDiagnosticsTrait) -> [String] {
let interfaces = trait.attributes.networkInterfaces ?? []
var ipAddresses: [String] = []
for interface in interfaces {
for data in interface.iPv4Addresses {
if let ipv4 = IPv4Address(data) {
ipAddresses.append(String(describing: ipv4))
}
}
for data in interface.iPv6Addresses {
if let ipv6 = IPv6Address(data) {
ipAddresses.append(String(describing: ipv6))
}
}
}
return ipAddresses
}
Sprawdzanie routingu sieciowego cechy
Lokalizacja cechy jest też dostępna w interfejsach API Google Home. dataSourceLocality wskazuje, czy cecha jest kierowana zdalnie (przez chmurę), lokalnie (przez lokalne centrum) czy w sieci peer-to-peer (bezpośrednio z urządzenia na urządzenie, bez centrum).
Nieznana wartość lokalizacji unspecified może wystąpić na przykład podczas uruchamiania aplikacji, gdy nie połączyła się ona jeszcze z centrum ani serwerem. Te urządzenia są nieosiągalne i nie będą reagować na żądania interakcji z poleceń lub zdarzeń. To klient decyduje, jak postępować z takimi urządzeniami.
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 być obserwowany w podobnym scenariuszu jak w przypadku połączenia partiallyOnline: niektóre cechy są działające w 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 pierwotna struktura HomeDevice pozostaje bez zmian, a zmiana jest odzwierciedlana w zwróconym zaktualizowanym obiekcie HomeDevice.
Nazwy zostaną obcięte, jeśli przekroczą limit 60 punktów kodowych Unicode (znaków). Nie zostaną wyświetlone żadne błędy. Deweloperzy są odpowiedzialni za obsługę długich nazw i mogą na przykład zdecydować, czy chcą informować użytkowników, że nazwy będą skracane.
Sprawdzanie członkostwa urządzenia w grupie
Urządzenie fizyczne może należeć do co najmniej 1 grupy urządzeń. Aby sprawdzić, do których grup należy urządzenie, sprawdź GroupMembershipTrait na urządzeniu:
if let trait = await device.traits.get(Google.GroupMembershipTrait.self) {
for groupId in trait.attributes.groupObjectIdsArray {
print("Device belongs to group: \(groupId)")
}
}
Aby sprawdzić typy urządzeń obsługiwane przez DeviceGroup i wysyłać polecenia do grupy jako pojedynczej encji, zapoznaj się z artykułem Sterowanie grupą urządzeń.