Typ urządzenia Dzwonek do drzwi jest implementowany za pomocą 3 cech:
PushAvStreamTransport,
która obsługuje transport strumieni audio i wideo za pomocą protokołów opartych na push,
WebRtcLiveView,
która umożliwia sterowanie transmisjami na żywo i funkcją TalkBack, oraz
CameraSnapshot,
która zapewnia zapisane w pamięci podręcznej podglądy i zrzuty na żywo.
Zanim użyjesz jakichkolwiek funkcji lub spróbujesz zaktualizować atrybuty, zawsze sprawdzaj, czy urządzenie obsługuje atrybuty i polecenia. Więcej informacji znajdziesz w sekcji Sterowanie urządzeniami naAndroid.
| Typ urządzenia interfejsów Home API | Cechy | Przykładowa aplikacja w Kotlinie | Przypadek użycia |
|---|---|---|---|
|
Dzwonek
Urządzenie uruchamiane przyciskiem na zewnątrz drzwi, które wysyła sygnał dźwiękowy lub wizualny, aby zwrócić uwagę osoby znajdującej się po drugiej stronie drzwi. Dzwonki do drzwi mogą mieć funkcje transmisji na żywo, dwukierunkowego połączenia głosowego lub wykrywania zdarzeń. |
Wymagane cechy google PushAvStreamTransport google WebRtcLiveView |
Dzwonek |
Uzyskiwanie podstawowych informacji o urządzeniu
Wdrożono w przykładowej aplikacji na Androida
Cechy BasicInformation
zawierają informacje takie jak nazwa dostawcy, identyfikator dostawcy, identyfikator produktu, nazwa produktu (zawiera informacje o modelu) i wersja oprogramowania urządzenia:
// Get device basic information. All general information traits are on the RootNodeDevice type. device.type(RootNodeDevice).first().standardTraits.basicInformation?.let { basicInformation -> println("vendorName ${basicInformation.vendorName}") println("vendorId ${basicInformation.vendorId}") println("productId ${basicInformation.productId}") println("productName ${basicInformation.productName}") println("softwareVersion ${basicInformation.softwareVersion}") }
Uzyskiwanie numeru seryjnego
Aby uzyskać numer seryjny urządzenia, użyj polecenia GetSerialNumber cechy ExtendedBasicInformation.
Przykład pokazuje zapisanie numeru seryjnego w zmiennej o nazwie serialNumber:
val basicInfo: ExtendedBasicInformation = device.getTrait(ExtendedBasicInformation) val serialNumber = basicInfo.getSerialNumber().serialNumber
szybkie odpowiedzi.
Funkcja szybkich odpowiedzi umożliwia użytkownikowi wysyłanie wstępnie zdefiniowanych wiadomości na dzwonek.
Ta funkcja jest dostępna tylko na dzwonkach. Lista predefiniowanych wiadomości jest dostępna dla aplikacji partnera, która może je wyświetlać użytkownikowi, aby mógł je wybrać. Gotowe wiadomości nie są edytowalne przez użytkowników.
Szybkie odpowiedzi są implementowane za pomocą cechy
PresetMessage.
Odtwarzanie gotowej wiadomości
Aby odtworzyć gotową wiadomość, wywołaj metodę
playPresetMessage
i przekaż jej jedną z wartości ciągu znaków znalezionych we właściwości
availablePhraseTypes.
import com.google.home.HomeDevice
import com.google.home.HomeException
import com.google.home.google.GoogleDoorbellDevice
import com.google.home.google.PresetMessage
import kotlinx.coroutines.flow.first
suspend fun playDoorbellPresetMessage(device: HomeDevice, phraseTypeString: String) {
try {
// 1. Retrieve the first snapshot of the doorbell device type
val doorbellDevice = device.type(GoogleDoorbellDevice).first()
// 2. Extract the PresetMessage trait
val presetMessageTrait = doorbellDevice.trait(PresetMessage)
if (presetMessageTrait == null) {
println("PresetMessage trait is not supported on this doorbell device.")
return
}
// 3. (Optional) Check available phrase types supported by the device
val availablePhrases = presetMessageTrait.availablePhraseTypes
if (availablePhrases != null) {
val phraseTypesList = availablePhrases.map { it.phraseType }
println("Supported quick response phrases: $phraseTypesList")
}
// 4. Send the playPresetMessage command to the doorbell
presetMessageTrait.playPresetMessage(phraseType = phraseTypeString)
println("Preset message command sent successfully.")
} catch (e: HomeException) {
println("Home API error occurred: ${e.message}")
} catch (e: Exception) {
println("Unexpected failure: ${e.message}")
}
}
Ustawianie języka wypowiedzi
Ustaw aktywny język mówiony urządzenia na określony region (np. „en_US”) za pomocą metody setActiveLocale cechy LocalizationConfiguration.
import java.util.Locale // Convert underscore format (en_US) to Java Locale fun String.toLocale(): Locale = Locale.forLanguageTag(this.replace('_', '-')) // Setting the active language val trait: LocalizationConfiguration = device.getTrait(LocalizationConfiguration) val selectedLocale = "en_US" // Target locale string trait.update { setActiveLocale(selectedLocale) }
Pobieranie najnowszej godziny kontaktu urządzenia z chmurą
Aby znaleźć ostatni czas, w którym urządzenie miało kontakt z chmurą, użyj atrybutu lastContactTimestamp cechy ExtendedGeneralDiagnostics:
fun getLastContactTimeStamp(trait: ExtendedGeneralDiagnostics): java.time.Instant { val timestamp = trait.lastContactTimestamp return Instant.ofEpochSecond(timestamp.toLong()) }
Ustawienia typu mocowania kamery
Cechy Mount zawierają ustawienia mocowania kamery i informacje o stanie. Możesz odczytywać atrybuty, takie jak stan montażu, typ wykrywania i nazwa typu montażu. Dodatkowo możesz użyć cechy Mount, aby zastąpić domyślną konfigurację typu mocowania.
// Get the Mount trait val mountTrait: Mount = device.getTrait(Mount) // Read the current mount state and detection type val mountState = mountTrait.mountState val mountDetectionType = mountTrait.mountDetectionType // Read the current mount type name val mountTypeName = mountTrait.mountTypeName // Update the mount type override mountTrait.update { setMountTypeOverride(MountTrait.MountTypeOverrideEnum.Official) }
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.
Wdrożono w przykładowej aplikacji na Androidaval doorbellConnectivity = doorbellDevice.metadata.sourceConnectivity.connectivityState
Stan PARTIALLY_ONLINE może wystąpić w przypadku różnych typów urządzeń, gdy nie ma połączenia z internetem.
Matter standardowe sygnały mogą być nadal dostępne online ze względu na lokalne przekierowywanie, ale sygnały oparte na chmurze będą niedostępne.
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żesz sformatować do standardowych ciągów 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()
Rozpocznij transmisję na żywo
Wdrożono w przykładowej aplikacji na Androida
Aby rozpocząć transmisję na żywo, wyślij ciąg protokołu SDP (Session Description Protocol) do metody startLiveView() cechy WebRtcLiveView, która zwraca obiekt WebRtcLiveViewTrait.StartLiveViewCommand.Response zawierający 3 wartości:
- SDP sesji.
- Czas trwania sesji w sekundach.
- Identyfikator sesji, który może być używany do przedłużania lub kończenia sesji.
suspend fun getWebRtcLiveViewTrait(cameraDevice: HomeDevice) { return cameraDevice.type(GoogleDoorbellDevice).trait(WebRtcLiveView).first { it?.metadata?.sourceConnectivity?.connectivityState == ConnectivityState.ONLINE } } // Start the live view suspend fun startCameraStream(trait: WebRtcLiveView, offerSdp: String) { val response = trait.startLiveView(offerSdp) // Response contains three fields (see below) return response } ... // This is used to manage the WebRTC connection val peerConnection: RTCPeerConnection = ... ... val startResponse = startCameraStream(sdp) val answerSdp = startResponse?.answerSdp val sessionDuration = startResponse?.liveSessionDurationSeconds val mediaSessionId = startResponse?.mediaSessionId peerConnection.setRemoteDescription(SessionDescription.Type.ANSWER, answerSdp)
Przedłużanie transmisji na żywo
Wdrożono w przykładowej aplikacji na Androida
Transmisje na żywo mają z góry określony czas trwania, po którym wygasają. Aby wydłużyć czas trwania aktywnego strumienia, wyślij prośbę o przedłużenie za pomocą metody WebRtcLiveView.extendLiveView():
// Assuming camera stream has just been started suspend fun scheduleExtension(trait: WebRtcLiveView, mediaSessionId: String, liveSessionDurationSeconds: UShort ) { delay(liveSessionDurationSeconds - BUFFER_SECONDS * 1000) val response = trait.extendLiveView(mediaSessionId) // returns how long the session will be live for return response.liveSessionDurationSeconds }
Włączanie i wyłączanie TalkBack
Wdrożono w przykładowej aplikacji na Androida
Aby uruchomić funkcję TalkBack, wywołaj metodę startTalkback()
cechy WebRtcLiveView. Aby zatrzymać, użyj stopTalkback().
// Make sure camera stream is on suspend fun setTalkback(isOn: Boolean, trait: WebRtcLiveView, mediaSessionId: String) { if(isOn) { trait.startTalkback(mediaSessionId) } else { trait.stopTalkback(mediaSessionId) } }
Włączanie i wyłączanie nagrywania
Aby włączyć funkcję nagrywania kamery, przekaż wartość
TransportStatusEnum.Active
do metody
PushAvStreamTransport
cechy
setTransportStatus(). Aby wyłączyć możliwość nagrywania, przekaż wartość
TransportStatusEnum.Inactive.
W przykładzie poniżej umieszczamy te wywołania w jednym wywołaniu, które używa Boolean do przełączania funkcji nagrywania:
// Start or stop recording for all connections. suspend fun setCameraRecording(trait: PushAvStreamTransport, isOn: Boolean) { if(isOn) { trait.setTransportStatus(TransportStatusEnum.Active) } else { trait.setTransportStatus(TransportStatusEnum.Inactive) } }
Włączenie lub wyłączenie możliwości nagrywania przez kamerę jest równoznaczne z włączeniem lub wyłączeniem nagrywania wideo z kamery. Gdy nagrywanie wideo z kamery jest włączone, kamera nagrywa (na potrzeby zdarzeń i powiązanych klipów).
Gdy funkcja nagrywania jest wyłączona (wideo z kamery jest wyłączone):
- Kamera może nadal być widoczna jako online zgodnie z
connectivityStatetypu urządzenia. - Nie można uzyskać dostępu do transmisji na żywo, a kamera nie wykrywa żadnych zdarzeń w chmurze.
Sprawdź, czy funkcja nagrywania jest włączona.
Aby sprawdzić, czy funkcja nagrywania kamery jest włączona, sprawdź, czy są aktywne jakiekolwiek połączenia. Poniższy przykład definiuje 2 funkcje, które to robią:
// Get the on/off state suspend fun onOffState(pushAvStreamTransport: PushAvStreamTransport) { return pushAvStreamTransport .currentConnections?.any { it.transportStatus == TransportStatusEnum.Active } ?: false } // Check if the camera's recording capability is enabled fun PushAvStreamTransport.recordModeActive(): Boolean { return currentConnections?.any { it.transportStatus == TransportStatusEnum.Active } ?: false }
Innym sposobem sprawdzenia jest użycie funkcji findTransport() z predykatem:
// Fetch the current connections suspend fun queryRecordModeState(trait: PushAvStreamTransport) { return trait.findTransport().let { it.transportConfigurations.any { it.transportStatus == TransportStatusEnum.Active } }
Pobieranie zrzutów z kamery
Wdrożono w przykładowej aplikacji na Androida
Użyj cechy CameraSnapshot, aby pobrać statyczne migawki z kamery.
Zrzuty te są przydatne w kilku scenariuszach:
- jako element zastępczy w interfejsie podczas wczytywania transmisji na żywo WebRTC;
- jako statyczny obraz podglądu, który po interakcji użytkownika przekształca się w transmisję na żywo;
- Jako tło do rysowania i konfigurowania niestandardowych stref aktywności.
Cechę CameraSnapshot można wykorzystać na 2 sposoby pobierania zrzutów w zależności od tego, czy potrzebujesz zrzutu z pamięci podręcznej do szybkiego renderowania, czy zrzutu na żywo na żądanie.
Wyświetlanie podglądu z pamięci podręcznej
Podgląd to obraz w pamięci podręcznej, który SDK może pobrać bez włączania aparatu. Jest to najszybsza metoda pobierania obrazu statycznego, która idealnie sprawdza się w przypadku stron z podsumowaniem informacji o kamerze lub siatek w panelu.
Aby uzyskać podgląd, odczytaj atrybut cechy preview_image_url:
// Get a flow of the CameraSnapshot trait val cameraSnapshotFlow: Flow<CameraSnapshot?> = cameraDevice .type(GoogleCameraDevice) .trait(CameraSnapshot) // Get the current trait state val cameraSnapshot = cameraSnapshotFlow.firstOrNull() if (cameraSnapshot != null) { val previewImageUrl = cameraSnapshot.previewImageUrl // Load the preview image from the URL } else { // CameraSnapshot trait not supported on this device }
W zależności od konfiguracji kamery i aktywności adres URL podglądu wskazuje obraz w pamięci podręcznej wygenerowany na podstawie ostatnich nagrań wideo (pierwsza klatka I najnowszego fragmentu wideo) lub zrzut okresowo przesyłany przez kamerę.
Aby wskazać, jak aktualny jest obraz, chmura Google Home osadza w przesyłanym obrazie JPEG/PNG nagłówek X-Home-Image-Captured-At w formacie UTC. Możesz przeanalizować ten nagłówek po stronie klienta, aby wyświetlić w aplikacji wiek migawki.
Uzyskiwanie zrzutu na żywo na żądanie
W przypadku ścieżek użytkownika, które wymagają bieżącego widoku na żywo z kamery, np. podczas konfigurowania miejsc aktywności, możesz poprosić o wykonanie zdjęcia na żywo. Wywołanie migawki na żywo powoduje, że kamera włącza się, robi nowe zdjęcie i przesyła je do chmury.
Aby poprosić o zrzut na żywo, użyj polecenia getLiveSnapshot():
try { val response = cameraSnapshot.getLiveSnapshot() val snapshotUrl = response.snapshotUrl // Load the live snapshot image from the URL } catch (e: Exception) { Log.e("CameraSnapshot", "Failed to get live snapshot: ${e.message}") }
Uwierzytelnianie żądań migawek
Wdrożono w przykładowej aplikacji na Androida
Wszystkie adresy URL migawek wskazują bezpieczne multimedia i wymagają tokena OAuth 2.0 w zakresie Home API w wersji 2. Aby pobrać i wyrenderować obrazy, token OAuth musi zostać wstrzyknięty jako token okaziciela w nagłówku Authorization żądania HTTP.
Poniższy przykład pokazuje, jak skonfigurować bezpieczne żądanie sieciowe pobrania migawki:
import android.graphics.Bitmap import android.graphics.BitmapFactory import java.io.IOException import java.net.HttpURLConnection import java.net.URL import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext /** * Downloads a snapshot from a URL using an OAuth access token. */ suspend fun loadSnapshotImage(urlString: String, oauthToken: String): Bitmap? = withContext(Dispatchers.IO) { var connection: HttpURLConnection? = null try { val url = URL(urlString) connection = url.openConnection() as HttpURLConnection // 1. Configure the HTTP GET request with the Bearer token connection.setRequestProperty("Authorization", "Bearer $oauthToken") // 2. Fetch the image data if (connection.responseCode == HttpURLConnection.HTTP_OK) { connection.inputStream.use { inputStream -> BitmapFactory.decodeStream(inputStream) } } else { null } } catch (e: IOException) { e.printStackTrace() null } finally { connection?.disconnect() } }
Zarządzanie transmisją na żywo
Dostosowywanie jakości transmisji na żywo jest przydatne do optymalizacji wykorzystania przepustowości na podstawie kontekstu oglądania przez klienta (np. przełączanie na niższą rozdzielczość podczas wyświetlania mniejszego kafelka podglądu, widoku siatki lub trybu obrazu w obrazie).
Dynamiczna zmiana jakości za pomocą atrybutu
WebRtcLiveView
umożliwia zarządzanie rozdzielczością aktywnej sesji transmisji na żywo
na konkretnym urządzeniu. Nie jest to to samo co skonfigurowanie ustawienia wykorzystania przepustowości na poziomie urządzenia bezpośrednio na urządzeniu, co wpłynęłoby na wszystkich widzów oglądających transmisję jednocześnie oraz na jakość historycznych nagrań wideo zapisanych w chmurze.
Poniższy przykład pokazuje, jak pobrać i zaktualizować jakość transmisji na żywo na urządzeniu:
Pobierz obsługiwane opcje jakości: uzyskaj dostępne rozdzielczości strumieniowania obsługiwane przez urządzenie. Kod wysyła zapytanie do atrybutu
WebRtcLiveViewcechysupportedQualityHintsw przepływie typu urządzenia i udostępnia obsługiwane jakości jakoStateFlowzawierający listę wartościQualityHint(np.QUALITY_HINT_SD,QUALITY_HINT_HD,QUALITY_HINT_FHD,QUALITY_HINT_QHDlubQUALITY_HINT_UHD).Zmień jakość transmisji na żywo: zastosuj wybraną opcję
QualityHint, aby zmienić rozdzielczość aktywnej transmisji na żywo (np. przejść z rozdzielczości standardowej na wysoką). FunkcjachangeQualityrozwiązuje cechę transmisji na żywo urządzenia i wywołuje funkcjęchangeLiveViewQualityz aktywną konfiguracjąmediaSessionIdi wybraną konfiguracjąQualityHint.
// Assuming you have a HomeDevice instance 'device' val availableQualityHints: StateFlow<List> = device.type(GoogleDoorbellDevice) .trait(WebRtcLiveView) .map { trait -> trait?.supportedQualityHints ?: emptyList() } .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList()) // Assuming you have a HomeDevice instance 'device' suspend fun changeQuality(mediaSessionId: String, qualityHint: QualityHint) { // Get the trait from the device val trait = device.type(GoogleDoorbellDevice).trait(WebRtcLiveView).first() ?: return try { trait.changeLiveViewQuality(mediaSessionId, qualityHint) } catch (e: Exception) { // Handle error } }
Ustawienia baterii
Różnymi ustawieniami baterii można sterować za pomocą interfejsów Home API.
Ustawianie preferencji dotyczących wykorzystania baterii
Ustawienie bilansu energetycznego umożliwia skonfigurowanie kompromisu między czasem pracy na baterii a wydajnością urządzenia. Możesz utworzyć różne profile baterii, takie jak „Wydłużony”, „Zrównoważony” i „Wydajność”, i przełączać się między nimi.
Ta funkcja jest wdrażana przez aktualizację atrybutu currentEnergyBalance cechy EnergyPreference. Atrybut przyjmuje liczbę całkowitą, która odpowiada konkretnemu profilowi zdefiniowanemu na liście energyBalances urządzenia (np. 0 dla EXTENDED, 1 dla BALANCED i 2 dla PERFORMANCE).
Wartość null w przypadku currentEnergyBalance oznacza, że urządzenie używa profilu niestandardowego. Jest to stan tylko do odczytu.
Poniżej znajdziesz przykład struktury, której będzie używać atrybut currentEnergyBalance, a następnie fragment kodu, który korzysta z tego atrybutu.
// Example energyBalances list energy_balances: [ { step: 0, label: "EXTENDED" }, { step: 50, label: "BALANCED" }, { step: 100, label: "PERFORMANCE" } ]
// The index parameter must be within the UByte range (0-255). suspend fun setEnergyBalance(trait: EnergyPreference, index: Int) { trait.update { setCurrentEnergyBalance(index.toUByte()) } } // Setting the battery usage to more recording ie performance setEnergyBalance(energyPreference, 2)
Włączanie automatycznego oszczędzania baterii
Aby skonfigurować tę funkcję, zaktualizuj atrybut currentLowPowerModeSensitivity w cechie EnergyPreference. Ten atrybut używa indeksu do wyboru poziomu czułości, gdzie 0 zwykle oznacza Disabled, a 1 oznacza Enabled lub Automatic.
suspend fun setAutomaticBatterySaver(enable: Boolean, trait: EnergyPreference) { // 0 is Disabled, 1 is Enabled val value = if (enable) 1.toUByte() else 0.toUByte() trait.update { setCurrentLowPowerModeSensitivity(value) } }
Pobieranie stanu ładowania baterii
Aby uzyskać bieżący stan ładowania urządzenia (ładowanie, pełne naładowanie lub brak ładowania), użyj atrybutu batChargeState
cechy PowerSource.
// Get the battery charging state val batteryChargeState = powerSource.batChargeState when (batteryChargeState) { PowerSourceTrait.BatChargeStateEnum.IsCharging -> "Charging" PowerSourceTrait.BatChargeStateEnum.IsAtFullCharge -> "Full" PowerSourceTrait.BatChargeStateEnum.IsNotCharging -> "Not Charging" else -> "Unknown" }
Sprawdzanie poziomu baterii
Aby uzyskać aktualny poziom baterii, użyj atrybutu batChargeLevel cechy PowerSource. Poziom to OK, Warning (niski) lub Critical.
// Get the battery charge level val batteryLevel = powerSourceTrait.batChargeLevel when (batteryLevel) { PowerSourceTrait.BatChargeLevelEnum.OK -> "OK" PowerSourceTrait.BatChargeLevelEnum.Warning -> "Warning" PowerSourceTrait.BatChargeLevelEnum.Critical -> "Critical" else -> "Unknown" }
Uzyskiwanie źródła zasilania
Aby określić źródło zasilania urządzenia, użyj atrybutów BatPresent i wiredPresent cechy PowerSource.
val trait: PowerSource val isWired = trait.wiredPresent val hasBattery = trait.batPresent
Sprawdź, czy bateria wymaga wymiany.
Atrybut batReplaceability
określa, czy baterii nie można wymienić, czy można ją wymienić samodzielnie lub w fabryce.
Atrybut
batReplacementNeeded
cechy
PowerSource
informuje, czy bateria wymaga wymiany.
// Get the battery replacement status val batteryStatus = powerSourceTrait.batReplacementNeeded if (batteryStatus) { println("Replace the battery.") }
Jeśli bateria jest wymieniana przez użytkownika, w sekcji
batReplacementDescription
znajduje się opis baterii, w tym informacje takie jak kształt, skład chemiczny i preferowany producent.
Ustawienia dźwięku
Za pomocą interfejsów Home API można sterować różnymi ustawieniami dźwięku.
Włączanie i wyłączanie mikrofonu
Aby włączyć lub wyłączyć mikrofon urządzenia, zaktualizuj atrybut microphoneMuted
cechy CameraAvStreamManagement za pomocą wbudowanej funkcji setMicrophoneMuted w języku Kotlin:
// Turn the device's microphone on or off suspend fun turnOffMicrophone(disableMicrophone: Boolean, trait: CameraAvStreamManagement) { trait.update { setMicrophoneMuted(disableMicrophone) } }
Włączanie i wyłączanie nagrywania dźwięku
Aby włączyć lub wyłączyć nagrywanie dźwięku na urządzeniu, zaktualizuj atrybut recordingMicrophoneMutedCameraAvStreamManagement za pomocą wbudowanej funkcji Kotlin setRecordingMicrophoneMuted:
// Turn audio recording on or off for the device suspend fun turnOffAudioRecording(disableAudioRecording: Boolean, trait: CameraAvStreamManagement) { trait.update { setRecordingMicrophoneMuted(disableAudioRecording) } }
Dostosowywanie głośności głośnika
Aby dostosować głośność głośnika urządzenia, zaktualizuj atrybut speakerVolumeLevel
cechy CameraAvStreamManagement za pomocą wbudowanej funkcji setSpeakerVolumeLevel w języku Kotlin:
// Adjust the camera speaker volume suspend fun adjustSpeakerVolume(volume: Int, trait: CameraAvStreamManagement) { trait.update { setSpeakerVolumeLevel(volume.toUbyte()) } }
Ustawienia miejsc aktywności
Wdrożono w przykładowej aplikacji na Androida
Cechą ZoneManagement jest interfejs do zarządzania niestandardowymi obszarami zainteresowania (miejscami aktywności) na kamerach i dzwonkach do drzwi.
Strefy te służą do filtrowania wykrywania zdarzeń (np. ruchu osoby lub pojazdu) w określonych obszarach w polu widzenia urządzenia.
Miejsca aktywności są konfigurowane przez użytkownika w aplikacji partnera, co umożliwia wyznaczanie stref na określonych obszarach w polu widzenia kamery. Zdefiniowane przez użytkownika strefy są następnie przekształcane w struktury używane przez ten atrybut. Więcej informacji o tym, jak działają miejsca aktywności, znajdziesz w artykule Konfigurowanie i używanie miejsc aktywności.
Strefy aktywności są zwykle definiowane za pomocą 2-wymiarowych współrzędnych kartezjańskich.
Cechy te zapewniają TwoDCartesianVertexStruct dla wierzchołków i TwoDCartesianZoneStruct
dla definicji strefy (nazwa, wierzchołki, kolor i użycie).
Sprawdzanie miejsc aktywności
Aby wyświetlić strefy aktywności, sprawdź atrybut zones
cechy ZoneManagement.
// 1. Obtain the trait flow from the device private val zoneManagementFlow: Flow= device.type(CAMERA_TYPE).flatMapLatest { it.trait(ZoneManagement) } // 2. Map the flow to the list of zone structures val activityZones: Flow<List<ZoneManagementTrait.ZoneInformationStruct>> = zoneManagementFlow.map { trait -> trait.zones ?: emptyList() }
Dodawanie strefy aktywności
Aby utworzyć nową strefę, użyj polecenia createTwoDCartesianZone. To polecenie przyjmuje obiekt TwoDCartesianZoneStruct, który określa nazwę, wierzchołki, kolor i użycie strefy.
W tym przykładzie pokazujemy, jak utworzyć strefę o nazwie „Front Porch” (Weranda) z 4 wierzchołkami w kolorze łososiowym (#F439A0), która będzie używana do wykrywania ruchu.
import com.google.home.google.ZoneManagement import com.google.home.google.ZoneManagementTrait import com.google.home.matter.serialization.OptionalValue /** * Creates a custom activity zone named "Front Porch" with a salmon color * configured for motion detection. */ suspend fun createFrontPorchZone(zoneManagement: ZoneManagement) { // 1. Define the vertices for the zone (2D Cartesian coordinates) // Values are typically scaled to a maximum defined by the device's twoDCartesianMax attribute. val vertices = listOf( ZoneManagementTrait.TwoDCartesianVertexStruct(x = 260u, y = 422u), ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1049u, y = 0u), ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048u, y = 0u), ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048u, y = 950u), ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1630u, y = 1349u), ZoneManagementTrait.TwoDCartesianVertexStruct(x = 880u, y = 2048u), ZoneManagementTrait.TwoDCartesianVertexStruct(x = 0u, y = 2048u), ZoneManagementTrait.TwoDCartesianVertexStruct(x = 638u, y = 1090u) ) // 2. Define the zone structure val newZone = ZoneManagementTrait.TwoDCartesianZoneStruct( name = "Front Porch", vertices = vertices, // Usage defines what the zone filters (for example, Motion, Person, Vehicle) use = listOf(ZoneManagementTrait.ZoneUseEnum.Motion), // Color is typically a hex string (for example, Salmon/Pink) color = OptionalValue.present("#F439A0") ) try { // 3. Execute the command to add the zone to the device zoneManagement.createTwoDCartesianZone(newZone) println("Successfully created activity zone.") } catch (e: Exception) { // Handle potential HomeException or Timeout println("Failed to create activity zone: ${e.message}") } }
Aktualizowanie strefy aktywności
Aby zaktualizować istniejącą strefę, użyj polecenia updateTwoDCartesianZone. To polecenie wymaga zoneId i zaktualizowanego TwoDCartesianZoneStruct.
private suspend fun ZoneManagement.updateZone( zoneId: UShort, zone: ZoneManagementTrait.TwoDCartesianZoneStruct ) { // Execute the command to update the zone this.updateTwoDCartesianZone(zoneId = zoneId, zone = zone) }
Usuwanie strefy aktywności
Aby usunąć strefę, użyj polecenia
removeZone
z określonym zoneId.
private suspend fun ZoneManagement.deleteZone(zoneId: UShort) { // Execute the command to remove the zone this.removeZone(zoneId = zoneId) }
Aktywatory zdarzeń dźwiękowych
Cecha AvStreamAnalysis udostępnia interfejs do zarządzania wyzwalaczami wykrywania zdarzeń na kamerach i dzwonkach do drzwi. Wyzwolenie na podstawie obrazu (np. wykrycie osób lub pojazdów) może być związane z określoną strefą, ale wyzwolenie na podstawie dźwięku jest zwykle konfigurowane na poziomie urządzenia.
W przypadku wykrywania dźwięku za pomocą EventTriggerTypeEnum dostępne są te typy reguł:
| Tryb | Wartość typu wyliczeniowego | Opis |
|---|---|---|
| Dźwięk | Sound |
Ogólne wykrywanie dźwięku. |
| Ktoś coś mówi | PersonTalking |
Wykrywa mowę. |
| Szczekanie psa | DogBark |
Wykrywa wokalizacje psów. |
| Odgłos tłuczonego szkła | GlassBreak |
wykrywa odgłos tłuczonego szkła; |
| Alarm z czujnika dymu | SmokeAlarm |
Wykrywa alarmy dymowe, często rozpoznawane po sygnale dźwiękowym T3 (3 krótkie sygnały dźwiękowe, po których następuje przerwa). |
| alarm z czujnika tlenku węgla | CoAlarm |
Wykrywa alarmy tlenku węgla (CO), które są zwykle rozpoznawane po sygnale dźwiękowym T4 (4 krótkie sygnały dźwiękowe, po których następuje przerwa). |
Sprawdzanie stanu wykrywania dźwięku
Aby wyświetlić użytkownikowi bieżący stan wykrywania dźwięku, musisz sprawdzić, co obsługuje urządzenie i co jest włączone przez sprzęt urządzenia. Sprawdź te 2 atrybuty:
W przypadku tworzenia aplikacji na Androida z użyciem Kotlin Flows zwykle obserwujesz cechę AvStreamAnalysis z HomeDevice.
// Example structure to store the data class EventTriggerAttribute(val type: EventTriggerTypeEnum, val enabled: Boolean) // 1. Obtain the trait flow from the device private val avStreamAnalysisFlow: Flow<AvStreamAnalysis> = device.traitFromType(AvStreamAnalysis, CAMERA_TYPES.first { device.has(it) }) // 2. Map the flow to a list of sound event attributes val soundEventTriggersState: Flow<List<EventTriggerAttribute>> = avStreamAnalysisFlow.map { trait -> // Get raw lists from the trait attributes val supported = trait.supportedEventTriggers ?: emptyList() val enabled = trait.enabledEventTriggers ?: emptyList() // Define sound-specific triggers to filter for val soundTypes = setOf( EventTriggerTypeEnum.Sound, EventTriggerTypeEnum.PersonTalking, EventTriggerTypeEnum.DogBark, EventTriggerTypeEnum.GlassBreak, EventTriggerTypeEnum.SmokeAlarm, EventTriggerTypeEnum.CoAlarm, ) // Filter and associate status supported .filter { soundTypes.contains(it) } .map { type -> EventTriggerAttribute( type = type, enabled = enabled.contains(type) ) } }
Aktualizowanie zestawu włączonych wyzwalaczy
Aby zaktualizować zestaw włączonych wyzwalaczy, użyj polecenia
SetOrUpdateEventDetectionTriggers
które przyjmuje listę struktur EventTriggerEnablement.
private suspend fun AvStreamAnalysis.updateEventTriggers( eventTriggers: List<EventTriggerAttribute> ) { val toUpdate = eventTriggers.map { EventTriggerEnablement( eventTriggerType = it.type, enablementStatus = if (it.enabled) { EnablementStatusEnum.Enabled } else { EnablementStatusEnum.Disabled }, ) } // Execute the command on the device setOrUpdateEventDetectionTriggers(toUpdate) }
Tryby nagrywania
Wdrożono w przykładowej aplikacji na Androida
Cechą RecordingMode jest interfejs do zarządzania nagrywaniem filmów i zdjęć na kamerach i dzwonkach. Umożliwia użytkownikom wybór między nagrywaniem ciągłym, nagrywaniem opartym na zdarzeniach a całkowitym wyłączeniem nagrywania (tylko podgląd na żywo).
Element RecordingModeEnum określa dostępne strategie nagrywania:
| Tryb | Wartość typu wyliczeniowego | Opis |
|---|---|---|
| Wyłączono | Disabled |
Nagrywanie jest całkowicie wyłączone. Używany głównie przez starsze urządzenia. |
| CVR (Continuous Video Recording) | Cvr |
Filmy są nagrywane przez całą dobę. Wymaga subskrypcji (np. Google Home Premium). |
| EBR (nagrywanie zdarzeń) | Ebr |
Nagrywanie jest aktywowane przez zdarzenia (osoba, ruch). Długość wideo zależy od czasu trwania wydarzenia i subskrypcji. |
| ETR (Event Triggered Recording) | Etr |
krótkie nagranie podglądu (np. 10 sekund) wywoływane przez zdarzenia; |
| Widok Live View | LiveView |
Nagrywanie jest wyłączone, ale użytkownicy nadal mogą oglądać transmisję na żywo. |
| Grafika | Images |
Gdy wystąpią zdarzenia, zamiast nagrań wideo rejestrowane są migawki. |
Sprawdzanie trybów nagrywania
Aby wyświetlić bieżącą konfigurację nagrywania, sprawdź atrybuty cechy RecordingMode:
supportedRecordingModes– wszystkie potencjalne trybyavailableRecordingModes– tryby do wyboruselectedRecordingMode– tryb aktywny
// 1. Obtain the trait flow from the device private val recordingModeTraitFlow: Flow= device.traitFromType(RecordingMode, CAMERA_TYPES.first { device.has(it) }) // 2. Map the flow to recording mode options data class RecordingModeOptions( val recordingMode: RecordingModeTrait.RecordingModeEnum, val index: Int, val available: Boolean, val readableString: String, ) private val recordingModeOptions: Flow<List > = recordingModeTraitFlow.map { trait -> val supported = trait.supportedRecordingModes?.map { it.recordingMode } ?: emptyList() val available = trait.availableRecordingModes?.map { it.toInt() } ?: emptyList() supported.withIndex().map { (index, mode) -> RecordingModeOptions( recordingMode = mode, index = index, available = available.contains(index), readableString = mode.toReadableString(), ) } }
Zmiana trybu nagrywania
Przed aktualizacją upewnij się, że wybrany indeks z atrybutu supportedRecordingModes
występuje w atrybucie availableRecordingModes.
Aby zaktualizować wybrany tryb, użyj funkcji
setSelectedRecordingMode, przekazując indeks wybranego trybu:
private suspend fun RecordingMode.updateRecordingMode(index: Int) { // Execute the command to update the selected mode this.setSelectedRecordingMode(index.toUByte()) }
Inne ustawienia
Za pomocą interfejsów Home API można sterować różnymi innymi ustawieniami.
Włączanie i wyłączanie widzenia w nocy
Aby włączyć lub wyłączyć widzenie w nocy w przypadku kamery, użyj TriStateAutoEnum, aby zaktualizować atrybut nightVision cechy CameraAvStreamManagement za pomocą wbudowanej funkcji setNightVision w języku Kotlin:
// Turn night vision on cameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.On) } // Turn night vision off CameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.Off) }
Zmiana jasności diody LED stanu
Aby zmienić jasność diody LED stanu, użyj
ThreeLevelAutoEnum
do zaktualizowania atrybutu
statusLightBrightness
cechy CameraAvStreamManagement za pomocą wbudowanej funkcji
setStatusLightBrightness Kotlin:
// Set the LED brightness to high cameraAvStreamManagement.update { setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.High) } // Set the LED brightness to low cameraAvStreamManagement.update { setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.Low) }
Zmiana obszaru widoku kamery
Widok z kamery jest taki sam jak w przypadku funkcji powiększania i kadrowania opisanej w artykule pomocy Powiększanie i ulepszanie obrazu z kamery Nest.
Obszar widoczny jest zdefiniowany w parametrze ViewportStruct, który zawiera 4 wartości używane jako współrzędne obszaru widocznego. Współrzędne są zdefiniowane w ten sposób:
(x1,y1) -- (x2,y1) | | (x1,y2) -- (x2,y2)
Określanie wartości parametru ViewportStruct zależy od interfejsu aplikacji i implementacji kamery. Aby ustawić obszar widoku filmu z kamery, zaktualizuj atrybut viewport
cechy CameraAvStreamManagement za pomocą ViewportStruct, używając wbudowanej funkcji setViewport w Kotlinie:
cameraAvStreamManagement .update { setViewport( CameraAvStreamManagementTrait.ViewportStruct( x1 = horizontalRange.rangeStart.roundToInt().toUShort(), x2 = horizontalRange.rangeEnd.roundToInt().toUShort(), y1 = verticalRange.rangeStart.roundToInt().toUShort(), y2 = verticalRange.rangeEnd.roundToInt().toUShort(), ) ) }
Włączanie i wyłączanie statystyk
Każde urządzenie może indywidualnie wyrazić zgodę na wysyłanie szczegółowych danych analitycznych do chmury Google Home (patrz interfejsy Cloud Monitoring for Home API).
Aby włączyć analizy na urządzeniu, ustaw właściwość analyticsEnabled obiektu ExtendedGeneralDiagnosticsTrait na wartość true. Gdy ustawisz analyticsEnabled,logUploadEnabled automatycznie przyjmie wartość true, co umożliwia przesyłanie plików dziennika analitycznego do chmury Google Home.
// Enable analytics extendedGeneralDiagnostics.update { setAnalyticsEnabled(true) } // Disable analytics extendedGeneralDiagnostics.update { setAnalyticsEnabled(false) }
Konfiguracje transportu i nagrywania
W tej sekcji znajdziesz ustawienia związane z jakością transmisji z kamery i wywoływaniem zdarzeń. Tymi ustawieniami zarządza cecha
PushAvStreamTransport.
Odczytywanie ustawień transportu
W tej sekcji pokazujemy, jak pobrać bieżącą konfigurację z kamery lub dzwonka. Pobiera cechę PushAvStreamTransport, wyszukuje konkretne połączenie użyte do nagrywania, a następnie wyodrębnia bieżące wartości jakości przepustowości, czułości wybudzania i maksymalnej długości zdarzenia.
val trait: PushAvStreamTransport = device.getTrait(PushAvStreamTransport) val connections = trait.findTransport().transportConfigurations // Locate the connection designated for recording val recordingConnection = connections.firstOrNull { it.transportOptions.getOrNull()?.streamUsage == StreamUsageEnum.Recording } val options = recordingConnection?.transportOptions?.getOrNull() // 1. Bandwidth Quality (Video Stream ID) val videoStreamId = options?.videoStreamId?.getOrNull() // 2. Wake-up Sensitivity (Motion Sensitivity) val wakeUpSensitivity = options?.triggerOptions?.motionSensitivity?.getOrNull() // 3. Max Event Length (Motion Trigger Time Control) val maxEventLength = options?.triggerOptions?.motionTimeControl?.getOrNull()?.maxDuration
Aktualizowanie ustawień transportu
W tej sekcji dowiesz się, jak zmienić ustawienia transportu.
Tworzy nowy TransportOptionsStruct zawierający nowe wartości, a następnie używa polecenia modifyPushTransport, aby wysłać te zaktualizowane ustawienia z powrotem na urządzenie i zastosować je do połączenia nagrywania znalezionego w poprzednim kroku.
Aby zmienić te ustawienia, użyj polecenia modifyPushTransport z parametrem TransportOptionsStruct.
val toUpdate = TransportOptionsStruct( videoStreamId = OptionalValue.present(2u), // e.g., Max Quality triggerOptions = TransportTriggerOptionsStruct( motionSensitivity = OptionalValue.present(5u), // e.g., Medium motionTimeControl = OptionalValue.present( TransportMotionTriggerTimeControlStruct(maxDuration = 30u) ) ) ) if (recordingConnection != null) { trait.modifyPushTransport( connectionId = recordingConnection.connectionId, transportOptions = toUpdate ) }
Określanie jakości przepustowości
Właściwość videoStreamId obiektu TransportOptionsStruct odpowiada
konkretnej konfiguracji strumienia wideo.
Aby uzyskać obsługiwane strumienie wideo, użyj atrybutu allocatedVideoStreams, który jest listą VideoStreamStructs.
z atrybutu CameraAvStreamManagement urządzenia.
Dostosowywanie czułości wybudzania urządzenia
Właściwość motionSensitivity atrybutu TransportTriggerOptionsStruct odpowiada tym wartościom:
| Etykieta | Wartość (UByte) |
|---|---|
| Niski | 1u |
| Średni | 5u |
| Wysoki | 10u |
Dostosowywanie maksymalnej długości wydarzenia
Właściwość maxDuration w obiekcie TransportMotionTriggerTimeControlStruct
odpowiada tym czasom trwania (w sekundach):
- 10u, 15u, 30u, 60u, 120u, 180u
Ustawienia gongu
Różnymi ustawieniami dzwonka można sterować za pomocą interfejsów Home API.
Zmiana dźwięku gongu
Aby zmienić dźwięk dzwonka, najpierw pobierz listę dźwięków dzwonka zainstalowanych na urządzeniu, korzystając z atrybutu installedChimeSounds cechy Chime:
// Get a list of chimes and identify the currently selected one private val doorbellChimeTraitFlow: Flow= device.traitFromType(Chime, GoogleDoorbellDevice) val chimeSounds = doorbellChimeTraitFlow.first().installedChimeSounds ?: emptyList()
Następnie zaktualizuj atrybut
selectedChime
cechy Chime za pomocą wbudowanej funkcji setSelectedChime Kotlin:
// Set the chime using the chimeId from the installed list chimeSounds.firstOrNull { it.name == name }?.let { setSelectedChime(it.chimeId) }
Używanie zewnętrznego dzwonka
Wdrożono w przykładowej aplikacji na Androida
Dzwonek można skonfigurować tak, aby używał zewnętrznego dzwonka, np. mechanicznego dzwonka zainstalowanego w domu. Należy to skonfigurować podczas instalacji dzwonka, aby uniknąć potencjalnych uszkodzeń zewnętrznego dzwonka.
Aby wskazać typ zainstalowanego dzwonka zewnętrznego, użyj ExternalChimeType, aby zaktualizować atrybut externalChime cechy Chime za pomocą wbudowanej funkcji setExternalChime w języku Kotlin:
// Indicate the external chime is mechanical chime.update { setExternalChime(ChimeTrait.ExternalChimeType.Mechanical) }
Zmiana czasu trwania zewnętrznego gongu
Czas dzwonienia zewnętrznego dzwonka w sekundach można skonfigurować za pomocą interfejsów Home API. Jeśli dzwonek zewnętrzny obsługuje czas trwania dzwonka, użytkownik może chcieć go skonfigurować.
Wartość ustawiona w tym miejscu zależy od specyfikacji zewnętrznego dzwonka i zalecanej długości dzwonka.
Aby zmienić czas trwania dzwonka zewnętrznego, zaktualizuj atrybut
externalChimeDurationSeconds
cechy Chime za pomocą wbudowanej funkcji
setExternalChimeDurationSeconds Kotlin:
// Change the external chime duration chime.update { setExternalChimeDurationSeconds(newDuration.toUShort()) }
Włączanie motywu dzwonka
Wdrożono w przykładowej aplikacji na Androida
Niektóre dzwonki mogą mieć dzwonki, które są dostępne dla użytkowników tylko przez ograniczony czas. Na przykład dzwonki związane ze świętami. Są one nazywane motywami dzwonka.
Aby sprawdzić, które motywy dzwonka są dostępne dla użytkownika, utwórz filtr przedziału czasowego i użyj go do filtrowania wyników polecenia getAvailableThemes() z cechy ChimeThemes. Zwraca listę dostępnych motywów, w tym ich nazwy.
Poniższy przykład pokazuje, jak filtrować listę.
Motyw jest uznawany za aktywny, jeśli bieżąca godzina mieści się w zakresie czasu rozpoczęcia i zakończenia (odpowiednio wartości startTimeSeconds i endTimeSeconds). Jeśli czas rozpoczęcia nie jest ustawiony, jest on uznawany za aktywny od początku. Jeśli nie ustawisz godziny zakończenia, będzie ona aktywna bezterminowo. Jeśli oba te elementy nie są określone, motyw jest zawsze aktywny.
// Get themes from the ChimeThemes trait fun List<ChimeThemesTrait.ThemeStruct>.filterTimeboxedThemes(): List<ChimeThemesTrait.ThemeStruct> { val now = timeSource.instant().epochSecond.toULong() return filter { chimeStruct: ChimeThemesTrait.ThemeStruct -> val startTime: ULong = chimeStruct.startTimeSeconds.getOrNull() ?: 0UL val endTime: ULong = chimeStruct.endTimeSeconds.getOrNull() ?: MAX_VALUE startTime <= now && now <= endTime } } val availableThemes = doorbellChimeThemesTraitFlow .first() .getAvailableThemes() .themes .filterTimeboxedThemes()
Gdy poznasz nazwę motywu, np. Christmas, możesz go wybrać za pomocą funkcji setSelectedTimeboxedThemeName() w atrybucie ChimeThemes:
// Select a theme using the ChimeThemes trait val themeToSelect = "Christmas" if (themeToSelect in availableThemeNames) { doorbellChimeThemesTraitFlow.first().setSelectedTimeboxedThemeName(themeToSelect) }
Ustawienia powiadomień o gościach
Możesz wysyłać zapytania dotyczące ustawień komunikatów o gościach w przypadku dzwonków i nimi zarządzać za pomocą interfejsów Home API, które mają cechę VisitorAnnouncement. Ten atrybut określa, czy obecność gościa jest ogłaszana na głośnikach lub wyświetlaczach Google, gdy ktoś użyje dzwonka.
Poniższy przykład pokazuje, jak sprawdzić, czy komunikaty o gościach są włączone, i jak zaktualizować to ustawienie:
// Read the current visitor announcements state val isEnabled = visitorAnnouncementTrait.visitorAnnouncementsEnabled // Toggle the visitor announcements setting visitorAnnouncementTrait.update { setVisitorAnnouncementsEnabled(true) }
Wycofywanie urządzenia
Aby usunąć dzwonek z budynku, wywołaj
device.decommissionDevice(). Wyłączenie urządzenia powoduje wyświetlenie użytkownikowi zarządzanego przez Google ekranu potwierdzenia z ostrzeżeniem, że cała historia całodobowych nagrań wideo, historia zdarzeń, klipy i dane z biblioteki znajomych twarzy zostaną trwale usunięte z całego domu.
Szczegółowe instrukcje i przykłady kodu znajdziesz w artykule Usuwanie urządzenia.