Dostęp do interfejsów Device API można uzyskać za pomocą interfejsów API Google Home na Androida. Zaimportuj te pakiety do aplikacji:
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id
Aby używać określonych typów urządzeń lub cech z interfejsami Device API, należy je zaimportować pojedynczo.
Aby na przykład użyć cechy Matter Włączanie/wyłączanie i typu urządzenia Wtyczka z funkcją włączania/wyłączania, zaimportuj do aplikacji te pakiety:
import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffPluginUnitDevice
Więcej informacji znajdziesz w artykule Model danych na Androidzie.
Obsługa błędów
Dowolna metoda w interfejsach Home API może wywołać błąd
HomeException, dlatego zalecamy używanie bloku try-catch do przechwytywania błędu HomeException we wszystkich wywołaniach.
Podczas obsługi HomeException sprawdź pola
error.code i
error.message, aby dowiedzieć się, co poszło nie tak. Mogą też występować kody błędów podrzędnych, więc wywołaj metodę
getSubErrorCodes() i sprawdź wynik.
Wszelkie nieobsługiwane wyjątki spowodują awarię aplikacji.
Więcej informacji znajdziesz w artykule na temat obsługi błędów.
Przykładowe polecenie znajdziesz w artykule Wysyłanie polecenia do urządzenia.
Przykładowe rozmowy
Pobieranie listy urządzeń
Gdy masz już odwołanie do instancji Structure, wywołanie devices() zwraca Flow urządzeń dostępnych dla Ciebie z tej struktury:
// 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()
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 Androidzie.
Odczytywanie stanu urządzenia
Zobacz przykład sprawdzania atrybutu OnOff z cechy włączania/wyłączania urządzenia. Korzystając z modelu danych cech interfejsów API Google Home, w którym ta cecha jest identyfikowana jako OnOff, możesz pobierać dane cech za pomocą klasy standardTraits typu urządzenia:
// 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()!!
Więcej informacji o funkcji przepływu w języku Kotlin znajdziesz w distinctUntilChanged.
Unieważnianie stanu w subskrypcji cechy
Interfejs TraitStateInvalidation umożliwia unieważnienie stanu pobranego przez subskrypcje na urządzeniu docelowym, jeśli stan nie jest prawidłowo raportowany.
Przykłady sytuacji, w których stan może nie być prawidłowo raportowany, obejmują używanie atrybutów w cechach Matter o jakości „C” lub implementację urządzenia, która nieoczekiwanie powoduje problem.
Ten interfejs API wymusza odczyt bieżącego stanu cechy i zwraca wynik za pomocą istniejących przepływów cech.
Pobierz cechę, a następnie uruchom na niej forceRead:
val onOffTrait = device.?type(DimmableLightDevice)?.map{it.trait(OnOff)}.first()
onOffTrait.forceRead()
Pobieranie listy cech typu urządzenia
Typy urządzeń powinny być używane jako punkt 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.
Aby uzyskać listę dostępnych cech typu urządzenia Ściemnialna lampa:
// 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()
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ć potencjalne niejasności co do tego, o którą cechę chodzi, instancja Trait, do której odwołuje się urządzenie, powinna być poprzedzona kwalifikującą przestrzenią nazw. W przypadku cech standardowych, czyli takich, które są analogiczne do klastrów standardowych Matter, użyj standardTraits. W przypadku cech Google użyj googleTraits:
// Accessing standard traits on the type. val onOffTrait: OnOff? = dimmableLightDevice.standardTraits.onOff val levelControlTrait: LevelControl? = dimmableLightDevice.standardTraits.levelControl
Aby uzyskać dostęp do cechy konkretnego producenta, odwołaj się do niej bezpośrednio:
// Accessing a custom trait on the type. val customTrait = dimmableLightDevice.trait(MyCustomTrait)
Pobieranie listy urządzeń z określoną cechą
Funkcji filter w Kotlinie można używać do dalszego doprecyzowywania wywołań interfejsu API. Aby na przykład uzyskać listę urządzeń w domu, które mają cechę Wł./wył.:
// Get all devices that support OnOff val onOffDevices: Flow<List<HomeDevice>> = home.devices().map { devices -> devices.filter { it.has(OnOff) } }
Pełną listę cech dostępnych w interfejsach API Google Home znajdziesz w interfejsie Trait.
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) val lightDevices = home.devices().map { devices -> devices.filter { it.has(DimmableLightDevice) || it.has(OnOffLightDevice) || it.has(ColorTemperatureLightDevice) || it.has(ExtendedColorLightDevice) } }
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, w filtrowanych przepływach należy uwzględnić wiele typów urządzeń.
Pełną listę typów urządzeń dostępnych w interfejsach API Google Home znajdziesz w interfejsie DeviceType.
Uzyskiwanie identyfikatora dostawcy lub identyfikatora produktu dla urządzenia
Atrybut BasicInformation zawiera informacje takie jak identyfikator dostawcy, identyfikator produktu, nazwa produktu i numer seryjny urządzenia:
// 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}")
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 (np. sterowanie urządzeniem i sugerowane automatyzacje) dla swoich urządzeń, warto sprawdzić, jaki jest główny typ urządzenia.
Najpierw sprawdź typy urządzenia za pomocą type(), a następnie określ typy główne:
val types = device.types().first() val primaryTypes = types.filter { it.metadata.isPrimaryType }
Sprawdzanie, czy cecha jest online
Aby sprawdzić połączenie cechy, użyj metody connectivityState():
val onOffConnectivity = onOffTrait?.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. Zwracany stan jest kombinacją stanów połączenia wszystkich cech na tym urządzeniu.
val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState
Stan PARTIALLY_ONLINE może być widoczny w przypadku różnych typów urządzeń, gdy nie ma połączenia z internetem.
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 cechy GeneralDiagnostics. Adresy są zwracane jako tablice bajtów, które można sformatować jako standardowe ciągi IPv4 lub IPv6:
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()
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 trybie 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.
val onOffLocality = onOffTrait?.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.
val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality
Stan MIXED może być widoczny w podobnym scenariuszu jak w przypadku połączenia PARTIALLY_ONLINE: niektóre cechy są działające w chmurze, a inne są lokalne.
Zmienianie nazwy urządzenia
Wywołaj metodę setName(), aby zmienić nazwę urządzenia:
mixerDevice.setName("Grendel")
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ź jego cechę GroupMembership:
val groupIds = device.trait(GroupMembershipTrait)?.groupObjectIds.orEmpty()
for (groupId in groupIds) {
println("HomeAPI", "Device belongs to group: $groupId")
}
Możesz też obserwować wszystkie urządzenia należące do DeviceGroup, wywołując proces devices() na DeviceGroup:
group.devices(enableMultipartDevices = true).collect { members ->
println("HomeAPI", "Group contains ${members.size} devices")
}
Aby sprawdzić typy urządzeń obsługiwane przez DeviceGroup i wysyłać polecenia do grupy jako pojedynczej jednostki, zapoznaj się z artykułem Sterowanie grupą urządzeń.