Тип устройства "Дверной звонок" реализован с помощью трех функций:
PushAvStreamTransport, которая обрабатывает передачу аудио- и видеопотоков с помощью протоколов на основе push-уведомлений;
WebRtcLiveView, которая позволяет управлять трансляциями и двусторонней связью; и
CameraSnapshot, которая предоставляет кешированные снимки экрана и позволяет делать снимки экрана в реальном времени.
Перед использованием функций или попыткой обновить атрибуты всегда проверяйте, поддерживаются ли они устройством. Подробнее о том, как управлять устройствами на сайтеAndroid…
| Тип устройства для Home API | Функции | Пример приложения на Kotlin | История успеха |
|---|---|---|---|
|
Дверной звонок
Устройство, которое активируется кнопкой снаружи двери и издает звуковой и/или визуальный сигнал, чтобы привлечь внимание человека, находящегося по другую сторону двери. Дверные звонки могут поддерживать доступные трансляции, двустороннюю связь и обнаружение событий. |
Обязательные характеристики google PushAvStreamTransport google WebRtcLiveView |
Дверной звонок |
Как получить основную информацию об устройстве
Реализовано в тестовом приложении для Android
BasicInformation
содержит такую информацию об устройстве, как название и идентификатор поставщика, идентификатор и название товара (включая информацию о модели), а также версию ПО:
// 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}") }
Получить серийный номер
Чтобы получить серийный номер устройства, используйте команду GetSerialNumber из черты ExtendedBasicInformation.
В примере показано, как сохранить серийный номер в переменной serialNumber:
val basicInfo: ExtendedBasicInformation = device.getTrait(ExtendedBasicInformation) val serialNumber = basicInfo.getSerialNumber().serialNumber
быстрые ответы.
Функция быстрых ответов позволяет пользователю отправлять на дверной звонок заранее заданные сообщения.
Эта функция доступна только на устройствах дверного звонка. Список стандартных сообщений доступен в приложении партнера, который может предложить пользователю выбрать одно из них. Готовые сообщения нельзя редактировать.
Функция быстрых ответов реализована с помощью черты PresetMessage.
Как воспроизвести заранее записанное сообщение
Чтобы воспроизвести стандартное сообщение, вызовите метод playPresetMessage, передав ему одно из строковых значений, найденных в свойстве 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}")
}
}
Как выбрать язык озвучивания
Установить для устройства активный разговорный язык с определенной локалью (например, "en_US") с помощью метода setActiveLocale из признака 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) }
Как узнать время последнего подключения устройства к облаку
Чтобы узнать, когда устройство в последний раз подключалось к облаку, используйте атрибут lastContactTimestamp из черты ExtendedGeneralDiagnostics:
fun getLastContactTimeStamp(trait: ExtendedGeneralDiagnostics): java.time.Instant { val timestamp = trait.lastContactTimestamp return Instant.ofEpochSecond(timestamp.toLong()) }
Настройки типа крепления камеры
Свойство Mount содержит настройки крепления камеры и информацию о ее статусе. Вы можете просматривать такие атрибуты, как статус подключения, тип обнаружения и название типа подключения. Кроме того, вы можете использовать признак Mount, чтобы переопределить конфигурацию типа монтирования по умолчанию.
// 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) }
Как проверить подключение устройства
На самом деле подключение устройства проверяется на уровне типа устройства, поскольку некоторые устройства поддерживают несколько типов. Возвращаемое состояние представляет собой сочетание состояний подключения для всех характеристик устройства.
Реализовано в тестовом приложении для Androidval doorbellConnectivity = doorbellDevice.metadata.sourceConnectivity.connectivityState
Статус PARTIALLY_ONLINE может наблюдаться в случае, если используются устройства разных типов и нет подключения к интернету.
Matter стандартных характеристик могут быть доступны онлайн благодаря локальной маршрутизации, но характеристики на основе облачных технологий будут недоступны.
Как узнать IP-адрес устройства
Чтобы найти IP-адрес устройства, используйте атрибут networkInterfaces признака GeneralDiagnostics. Адреса возвращаются в виде массивов байтов, которые можно отформатировать в стандартные строки IPv4 или 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()
Как начать трансляцию
Реализовано в тестовом приложении для Android
Чтобы начать трансляцию, отправьте строку протокола описания сеанса (SDP) в метод startLiveView() признака WebRtcLiveView. В ответ вы получите WebRtcLiveViewTrait.StartLiveViewCommand.Response, содержащий три значения:
- SDP для сеанса.
- Длительность сеанса в секундах.
- Идентификатор сеанса, который можно использовать для его продления или завершения.
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)
Как продлить трансляцию
Реализовано в тестовом приложении для Android
У трансляций есть ограничение по длительности, по достижении которого они автоматически прекращаются. Чтобы увеличить продолжительность активного потока, отправьте запрос на продление с помощью метода 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 }
Как включить и отключить TalkBack
Реализовано в тестовом приложении для Android
Чтобы запустить TalkBack, вызовите метод startTalkback() из WebRtcLiveView. Чтобы остановить запись, нажмите 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) } }
Как включить и отключить возможность записи
Чтобы включить запись с камеры, передайте значение TransportStatusEnum.Active методу setTransportStatus() признака PushAvStreamTransport. Чтобы отключить возможность записи, передайте его
TransportStatusEnum.Inactive.
В приведенном ниже примере эти вызовы объединены в один, в котором используется Boolean для включения и отключения записи:
// 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) } }
Включение и отключение записи видео камерой аналогично включению и отключению видео с камеры. Когда видео с камеры включено, она записывает видео (для событий и связанных с ними клипов).
Если запись отключена (видео с камеры отключено):
- Камера может по-прежнему отображаться как онлайн в соответствии с
connectivityStateтипа устройства. - Нет доступа к трансляции, а камера не обнаруживает облачных событий.
Проверьте, включена ли возможность записи
Чтобы узнать, включена ли запись с камеры, проверьте, есть ли активные подключения. В примере ниже определены две функции, которые выполняют эту задачу:
// 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 }
Также можно использовать функцию findTransport() с предикатом:
// Fetch the current connections suspend fun queryRecordModeState(trait: PushAvStreamTransport) { return trait.findTransport().let { it.transportConfigurations.any { it.transportStatus == TransportStatusEnum.Active } }
Получать снимки с камеры
Реализовано в тестовом приложении для Android
Используйте функцию CameraSnapshot, чтобы получать статические снимки с камеры.
Снимки полезны в следующих случаях:
- В качестве заполнителя в интерфейсе, пока загружается трансляция WebRTC.
- В виде статического изображения, которое при взаимодействии с пользователем превращается в прямую трансляцию.
- В качестве фона для рисования и настройки специальных зон активности.
Свойство CameraSnapshot позволяет получать снимки двумя способами в зависимости от того, нужен ли вам кешированный снимок для быстрой отрисовки или снимок по запросу.
Как получить снимок из кеша
Предварительный снимок – это сохраненное в кеше изображение, которое SDK может получить, не включая камеру. Это самый быстрый способ получить статичное изображение, который идеально подходит для страниц обзора камеры или сеток на панели управления.
Чтобы получить снимок предпросмотра, прочитайте атрибут признака 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 }
В зависимости от конфигурации камеры и действий пользователя URL предпросмотра ведет на кешированное изображение, созданное на основе недавней видеозаписи (первый I-кадр последнего фрагмента видео), или на снимок, периодически загружаемый камерой.
Чтобы указать, когда было сделано изображение, облако Google Home встраивает заголовок X-Home-Image-Captured-At в полученное изображение JPEG/PNG, отформатированное в формате UTC. Вы можете выполнить синтаксический анализ этого заголовка на клиентской стороне, чтобы показывать возраст снимка в приложении.
Как получить снимок экрана в реальном времени
Если вам нужно посмотреть текущую трансляцию с камеры, например чтобы настроить зоны слежения, вы можете запросить снимок. При срабатывании функции создания снимка камера включается, делает новый кадр и загружает его в облако.
Чтобы запросить снимок в реальном времени, используйте команду 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}") }
Как аутентифицировать запросы снимков
Реализовано в тестовом приложении для Android
Все URL снимков указывают на защищенные медиафайлы и требуют токен OAuth 2.0 для области действия Home APIs v2. Чтобы скачать и обработать изображения, токен OAuth необходимо внедрить в качестве токена на предъявителя в заголовок Authorization HTTP-запроса.
В примере ниже показано, как настроить безопасный сетевой запрос для скачивания снимка:
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() } }
Как управлять трансляцией
Изменение качества трансляции позволяет оптимизировать использование пропускной способности сети в зависимости от контекста просмотра (например, переключаться на более низкое разрешение при показе небольшого фрагмента, сетки или в режиме "картинка в картинке").
Динамическое изменение качества с помощью функции
WebRtcLiveView
позволяет управлять разрешением активной сессии трансляции на определенном клиенте. Это не то же самое, что настроить использование пропускной способности на уровне устройства, поскольку в этом случае будут затронуты все пользователи, одновременно просматривающие видео, и качество видеозаписей, сохраненных в облаке.
В следующем примере показано, как получить и обновить качество трансляции для устройства:
Получение поддерживаемых вариантов качества. Узнайте, какие разрешения потоковой передачи поддерживает устройство. Код запрашивает атрибут
supportedQualityHintsтипа устройства в рамках функцииWebRtcLiveViewи предоставляет поддерживаемые качества в видеStateFlow, содержащего список значенийQualityHint(например,QUALITY_HINT_SD,QUALITY_HINT_HD,QUALITY_HINT_FHD,QUALITY_HINT_QHDилиQUALITY_HINT_UHD).Изменить качество трансляции: применить выбранный
QualityHint, чтобы изменить разрешение активной трансляции (например, переключиться со стандартного разрешения на высокое). ФункцияchangeQualityопределяет характеристику устройства для стриминга и вызывает функциюchangeLiveViewQualityс активной конфигурациейmediaSessionIdи выбранной конфигурацией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 } }
Настройки батареи
Различные настройки батареи можно контролировать с помощью API Home.
Как задать настройки расхода заряда батареи
Настройка баланса энергопотребления позволяет выбрать оптимальное соотношение между временем работы от батареи и производительностью устройства. Вы можете создать несколько профилей батареи, например "Экономия заряда", "Сбалансированный" и "Производительность", и переключаться между ними.
Эта функция реализована путем обновления атрибута currentEnergyBalance в чертеже EnergyPreference. Атрибут принимает целочисленный индекс, соответствующий определенному профилю в списке energyBalances устройства (например, 0 для EXTENDED, 1 для BALANCED и 2 для PERFORMANCE).
Значение null для параметра currentEnergyBalance указывает, что на устройстве используется специальный профиль. Это состояние доступно только для чтения.
Ниже приведен пример структуры, которую использует атрибут "цена со скидкой" currentEnergyBalance, а затем фрагмент кода, в котором используется этот атрибут.
// 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)
Как включить автоматический режим энергосбережения
Чтобы настроить эту функцию, обновите атрибут currentLowPowerModeSensitivity черты EnergyPreference. В этом атрибуте для выбора уровня конфиденциальности используется индекс, где 0 обычно соответствует Disabled, а 1 – Enabled или 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) } }
Как узнать состояние зарядки батареи
Чтобы узнать текущее состояние зарядки устройства (заряжается, полностью заряжено или не заряжается), используйте атрибут batChargeState из трейта 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" }
Как узнать уровень заряда батареи
Чтобы получить текущий уровень заряда батареи, используйте атрибут batChargeLevel из черты PowerSource. Уровень может быть OK, Warning (низкий) или 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" }
Как узнать источник питания
Чтобы определить, какой источник питания использует устройство, воспользуйтесь атрибутами BatPresent и wiredPresent признака PowerSource.
val trait: PowerSource val isWired = trait.wiredPresent val hasBattery = trait.batPresent
Проверьте, нужно ли заменить батарею.
Атрибут batReplaceability указывает, можно ли заменить батарею самостоятельно или это можно сделать только на заводе.
Атрибут batReplacementNeeded признака PowerSource указывает, нужно ли заменить батарею.
// Get the battery replacement status val batteryStatus = powerSourceTrait.batReplacementNeeded if (batteryStatus) { println("Replace the battery.") }
Если батарею может заменить пользователь, в разделе batReplacementDescription
приводится описание батареи, в том числе ее форм-фактор, химический состав и предпочтительный производитель.
Настройки звука
С помощью API Home можно управлять различными настройками аудио.
Включить или выключить микрофон
Чтобы включить или отключить микрофон устройства, обновите атрибут microphoneMuted
черты CameraAvStreamManagement, используя встроенную функцию Kotlin setMicrophoneMuted:
// Turn the device's microphone on or off suspend fun turnOffMicrophone(disableMicrophone: Boolean, trait: CameraAvStreamManagement) { trait.update { setMicrophoneMuted(disableMicrophone) } }
Как включить или отключить запись аудио
Чтобы включить или отключить аудиозапись на устройстве, обновите атрибут recordingMicrophoneMuted трейта CameraAvStreamManagement, используя встроенную функцию Kotlin setRecordingMicrophoneMuted:
// Turn audio recording on or off for the device suspend fun turnOffAudioRecording(disableAudioRecording: Boolean, trait: CameraAvStreamManagement) { trait.update { setRecordingMicrophoneMuted(disableAudioRecording) } }
Как настроить громкость колонки
Чтобы изменить громкость динамика устройства, обновите атрибут speakerVolumeLevel
черты CameraAvStreamManagement, используя встроенную функцию Kotlin setSpeakerVolumeLevel:
// Adjust the camera speaker volume suspend fun adjustSpeakerVolume(volume: Int, trait: CameraAvStreamManagement) { trait.update { setSpeakerVolumeLevel(volume.toUbyte()) } }
Настройки зон слежения
Реализовано в тестовом приложении для Android
Свойство ZoneManagement предоставляет интерфейс для управления пользовательскими областями интереса (зонами слежения) на камерах и дверных звонках.
Эти зоны используются для фильтрации обнаружения событий (например, движения человека или транспортного средства) в определенных областях в зоне обзора устройства.
Пользователь настраивает зоны слежения в приложении партнера, выбирая области в поле зрения камеры. Затем эти зоны, заданные пользователем, преобразуются в структуры, используемые этим свойством. Подробнее о том, как настроить и использовать зоны слежения…
Зоны активности обычно определяются с помощью двумерных декартовых координат.
Этот признак содержит TwoDCartesianVertexStruct для вершин и TwoDCartesianZoneStruct для определения зоны (название, вершины, цвет и использование).
Проверьте зоны слежения
Чтобы отобразить зоны слежения, проверьте атрибут zones
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() }
Как добавить зону активности
Чтобы создать новую зону, используйте команду createTwoDCartesianZone. Эта команда принимает TwoDCartesianZoneStruct, в котором задаются название, вершины, цвет и назначение зоны.
В следующем примере показано, как создать зону под названием "Передний двор" с четырьмя вершинами, окрашенную в цвет лосося (#F439A0) и используемую для обнаружения движения.
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}") } }
Как изменить зону активности
Чтобы обновить существующую зону, используйте команду updateTwoDCartesianZone. Для этой команды требуется zoneId и обновленный TwoDCartesianZoneStruct.
private suspend fun ZoneManagement.updateZone( zoneId: UShort, zone: ZoneManagementTrait.TwoDCartesianZoneStruct ) { // Execute the command to update the zone this.updateTwoDCartesianZone(zoneId = zoneId, zone = zone) }
Как удалить зону активности
Чтобы удалить зону, используйте команду removeZone с определенным значением zoneId.
private suspend fun ZoneManagement.deleteZone(zoneId: UShort) { // Execute the command to remove the zone this.removeZone(zoneId = zoneId) }
Триггеры звуковых событий
Свойство AvStreamAnalysis предоставляет интерфейс для управления триггерами обнаружения событий на камерах и дверных звонках. Триггеры, основанные на распознавании образов (например, людей или автомобилей), могут быть настроены для определенных зон, а звуковые триггеры обычно настраиваются на уровне устройства.
Для распознавания звуков с помощью EventTriggerTypeEnum доступны следующие типы триггеров:
| Режим | Перечисляемое значение | Описание |
|---|---|---|
| Звук | Sound |
Общее распознавание звуков. |
| Речь | PersonTalking |
Распознает речь. |
| Лай собаки | DogBark |
Распознает звуки, издаваемые собаками. |
| Звук бьющегося стекла | GlassBreak |
Распознает звук разбивающегося стекла. |
| Датчик дыма | SmokeAlarm |
Распознает звуки пожарной сигнализации, которые часто имеют звуковой шаблон T3 (три коротких звуковых сигнала с последующей паузой). |
| Датчик угарного газа | CoAlarm |
Обнаруживает сигналы тревоги, связанные с угарным газом, которые обычно распознаются по звуковому сигналу T4 (четыре коротких звуковых сигнала, за которыми следует пауза). |
Как проверить статус распознавания звуков
Чтобы показать пользователю текущее состояние распознавания звуков, необходимо проверить, что поддерживается устройством и что включено аппаратным обеспечением устройства. Проверьте следующие атрибуты:
При разработке приложений для Android с использованием Kotlin Flows обычно наблюдается признак AvStreamAnalysis из 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) ) } }
Как изменить набор включенных триггеров
Чтобы обновить набор включенных триггеров, используйте команду SetOrUpdateEventDetectionTriggers, которая принимает список структур 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) }
Режимы записи
Реализовано в тестовом приложении для Android
Свойство RecordingMode предоставляет интерфейс для управления записью видео и изображений на камерах и дверных звонках. Пользователи могут выбрать непрерывную запись, запись событий или отключить запись (только просмотр трансляции с камеры).
RecordingModeEnum определяет доступные стратегии записи:
| Режим | Перечисляемое значение | Описание |
|---|---|---|
| Отключено | Disabled |
Запись полностью отключена. Используется в основном устаревшими устройствами. |
| Непрерывная видеозапись | Cvr |
Видео записывается круглосуточно. Требуется подписка (например, Google Home Premium). |
| EBR (запись на основе событий) | Ebr |
Запись запускается при обнаружении движения или человека. Продолжительность видео зависит от длительности мероприятия и подписки. |
| ETR (запись по триггеру события) | Etr |
Короткая запись предварительного просмотра (например, 10 секунд), запускаемая событиями. |
| Трансляция с камеры | LiveView |
Запись отключена, но пользователи по-прежнему могут смотреть трансляцию. |
| Картинки | Images |
При возникновении событий вместо видео записываются снимки. |
Проверьте режимы записи
Чтобы посмотреть текущую конфигурацию записи, проверьте атрибуты черты RecordingMode:
supportedRecordingModes– все возможные режимы.availableRecordingModes– режимы, которые можно выбрать.selectedRecordingMode– активный режим.
// 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(), ) } }
Как изменить режим записи
Перед обновлением убедитесь, что выбранный индекс из атрибута "индекс" supportedRecordingModes присутствует в атрибуте "индекс" availableRecordingModes.
Чтобы обновить выбранный режим, используйте функцию setSelectedRecordingMode, передав индекс выбранного режима:
private suspend fun RecordingMode.updateRecordingMode(index: Int) { // Execute the command to update the selected mode this.setSelectedRecordingMode(index.toUByte()) }
Другие настройки
Через API Home можно управлять различными другими настройками.
Как включить или отключить ночное видение
Чтобы включить или отключить ночное видение для камеры, используйте TriStateAutoEnum, чтобы обновить атрибут nightVision признака CameraAvStreamManagement с помощью встроенной функции Kotlin setNightVision:
// Turn night vision on cameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.On) } // Turn night vision off CameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.Off) }
Как изменить яркость индикатора состояния
Чтобы изменить яркость светодиодного индикатора состояния, используйте ThreeLevelAutoEnum, чтобы обновить атрибут statusLightBrightness черты CameraAvStreamManagement с помощью встроенной функции Kotlin setStatusLightBrightness:
// Set the LED brightness to high cameraAvStreamManagement.update { setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.High) } // Set the LED brightness to low cameraAvStreamManagement.update { setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.Low) }
Как изменить область просмотра камеры
Область просмотра камеры – это то же самое, что и функция масштабирования и кадрирования, описанная в статье о масштабировании и улучшении видео с камеры Nest.
Область просмотра определяется в объекте ViewportStruct, который содержит четыре значения, используемые в качестве координат области просмотра. Координаты определяются следующим образом:
(x1,y1) -- (x2,y1) | | (x1,y2) -- (x2,y2)
Значения для ViewportStruct зависят от интерфейса приложения и реализации камеры. Чтобы задать область просмотра видео с камеры, обновите атрибут viewport признака CameraAvStreamManagement с помощью ViewportStruct, используя встроенную функцию Kotlin setViewport:
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(), ) ) }
Как включить или отключить аналитику
Каждое устройство может отдельно отправлять подробные аналитические данные в облако Google Home (см. Cloud Monitoring for Home APIs).
Чтобы включить аналитику для устройства, задайте для свойства analyticsEnabled объекта ExtendedGeneralDiagnosticsTrait значение true. Когда вы задаете значение analyticsEnabled, другой параметр, logUploadEnabled, автоматически получает значение true, что позволяет загружать файлы журналов аналитики в облако Google Home.
// Enable analytics extendedGeneralDiagnostics.update { setAnalyticsEnabled(true) } // Disable analytics extendedGeneralDiagnostics.update { setAnalyticsEnabled(false) }
Конфигурации транспорта и записи
В этом разделе описаны настройки, связанные с качеством трансляции с камеры и запуском событий. Этими настройками управляет черта PushAvStreamTransport.
Чтение настроек транспорта
В этом разделе рассказывается, как получить текущую конфигурацию с камеры или дверного звонка. Он получает трейт PushAvStreamTransport, находит подключение, которое использовалось для записи, а затем извлекает текущие значения качества пропускной способности, автоматического выхода из спящего режима и максимальной длительности события.
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
Как изменить настройки транспорта
В этом разделе рассказывается, как изменить настройки транспорта.
Он создает новую переменную TransportOptionsStruct, содержащую новые значения, а затем использует команду modifyPushTransport, чтобы отправить эти обновленные настройки обратно на устройство и применить их к подключению для записи, найденному на предыдущем шаге.
Чтобы изменить эти настройки, используйте команду modifyPushTransport с 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 ) }
Как определить качество пропускной способности
Свойство videoStreamId объекта TransportOptionsStruct соответствует определенной конфигурации видеопотока.
Чтобы получить список поддерживаемых видеопотоков, используйте атрибут allocatedVideoStreams, который представляет собой список VideoStreamStructs.
из признака CameraAvStreamManagement для устройства.
Как настроить чувствительность вывода устройства из спящего режима
Свойство motionSensitivity объекта TransportTriggerOptionsStruct соответствует следующим значениям:
| Ярлык | Значение (UByte) |
|---|---|
| Низкая | 1U |
| Средний | 5u |
| Высокий | 10u |
Как изменить максимальную продолжительность события
Свойство maxDuration объекта TransportMotionTriggerTimeControlStruct соответствует следующим значениям продолжительности (в секундах):
- 10u, 15u, 30u, 60u, 120u, 180u
Настройки звонка
Различными настройками дверного звонка можно управлять через Home API.
Как изменить звук звонка
Чтобы изменить звук дверного звонка, сначала получите список звуков звонка, установленных на устройстве, с помощью атрибута installedChimeSounds трейта 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()
Затем обновите атрибут selectedChime признака Chime, используя встроенную функцию setSelectedChime Kotlin:
// Set the chime using the chimeId from the installed list chimeSounds.firstOrNull { it.name == name }?.let { setSelectedChime(it.chimeId) }
Как использовать внешний звонок
Реализовано в тестовом приложении для Android
Звонок можно настроить так, чтобы он использовал внешний звонок, например механический, установленный в доме. Это нужно сделать во время установки дверного звонка, чтобы избежать повреждения внешнего звонка.
Чтобы указать тип установленного внешнего звонка, используйте ExternalChimeType, чтобы обновить атрибут externalChime признака Chime с помощью встроенной функции Kotlin setExternalChime:
// Indicate the external chime is mechanical chime.update { setExternalChime(ChimeTrait.ExternalChimeType.Mechanical) }
Как изменить длительность внешнего звонка
Продолжительность звонка внешнего звонка в секундах можно настроить с помощью API Google Home. Если внешний звонок поддерживает настройку длительности, пользователь может захотеть ее задать.
Значение зависит от характеристик внешнего звонка и рекомендованной длительности сигнала.
Чтобы изменить продолжительность внешнего звонка, обновите атрибут externalChimeDurationSeconds признака Chime, используя встроенную функцию Kotlin setExternalChimeDurationSeconds:
// Change the external chime duration chime.update { setExternalChimeDurationSeconds(newDuration.toUShort()) }
Как включить тему звонка
Реализовано в тестовом приложении для Android
У некоторых дверных звонков есть мелодии, которые доступны пользователям только в течение ограниченного времени. Например, мелодии, связанные с праздниками. Это называется темами звонков.
Чтобы узнать, какие темы доступны пользователю, создайте фильтр временного интервала и примените его для фильтрации результатов команды getAvailableThemes() из черты ChimeThemes. В результате будет показан список доступных тем, в том числе их названия.
В следующем примере показано, как отфильтровать список.
Тема считается активной, если текущее время находится в диапазоне между временем начала и окончания (значения startTimeSeconds и endTimeSeconds соответственно). Если время начала не задано, считается, что правило активно с начала времен. Если время окончания не задано, правило будет действовать бессрочно. Если оба параметра отсутствуют, тема всегда активна.
// 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()
Если вы знаете название нужной темы, например Christmas, вы можете выбрать ее с помощью функции setSelectedTimeboxedThemeName() в рамках признака ChimeThemes:
// Select a theme using the ChimeThemes trait val themeToSelect = "Christmas" if (themeToSelect in availableThemeNames) { doorbellChimeThemesTraitFlow.first().setSelectedTimeboxedThemeName(themeToSelect) }
Настройки объявлений для посетителей
Вы можете запрашивать и изменять настройки уведомлений о посетителях для дверных звонков с помощью черты VisitorAnnouncement API Home. Этот признак определяет, будет ли объявляться о присутствии посетителя на умных колонках или дисплеях Google, когда кто-то звонит в дверной звонок.
В примере ниже показано, как проверить, включены ли уведомления о посетителях, и как изменить эту настройку.
// Read the current visitor announcements state val isEnabled = visitorAnnouncementTrait.visitorAnnouncementsEnabled // Toggle the visitor announcements setting visitorAnnouncementTrait.update { setVisitorAnnouncementsEnabled(true) }
Как списать устройство
Чтобы удалить дверной звонок из структуры, вызовите метод device.decommissionDevice(). При отключении пользователю показывается управляемый Google экран подтверждения с предупреждением о том, что все записанные видео, архив событий, клипы и данные библиотеки знакомых лиц будут безвозвратно удалены из структуры.
Подробные инструкции и примеры кода приведены в статье Как удалить устройство.