Тип устройства "Камера" реализуется с помощью трех признаков:
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
Получить время последнего подключения устройства к облаку
Чтобы узнать, когда устройство в последний раз подключалось к облаку, используйте атрибут 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) }
Как проверить подключение устройства
Подключение устройства проверяется на уровне типа устройства, поскольку некоторые устройства поддерживают несколько типов. Возвращаемое состояние представляет собой комбинацию состояний подключения для всех характеристик на этом устройстве.
val cameraConnectivity = cameraDevice.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 (Session Description Protocol) в метод startLiveView() типажа WebRtcLiveView. Метод возвращает объект WebRtcLiveViewTrait.StartLiveViewCommand.Response, содержащий три значения:
- SDP для сеанса.
- Длительность сеанса в секундах.
- Идентификатор сеанса, который можно использовать для продления или завершения сеанса.
suspend fun getWebRtcLiveViewTrait(cameraDevice: HomeDevice) { return cameraDevice.type(GoogleCameraDevice).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
Чтобы начать обратную связь, вызовите метод 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) } }
Управление трансляцией
Настройка качества трансляции позволяет оптимизировать использование пропускной способности в зависимости от контекста просмотра клиента (например, переключение на более низкое разрешение при отображении меньшего фрагмента предварительного просмотра, в виде сетки или режима "картинка в картинке").
Динамическое изменение качества с помощью свойства 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(GoogleCameraDevice) .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(GoogleCameraDevice).trait(WebRtcLiveView).first() ?: return try { trait.changeLiveViewQuality(mediaSessionId, qualityHint) } catch (e: Exception) { // Handle error } }
Как включить или отключить функцию записи
Чтобы включить запись с камеры, передайте 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() } }
Настройки батареи
Home API позволяют управлять различными настройками батареи.
Как настроить расход заряда батареи
Настройка баланса энергопотребления позволяет выбрать соотношение между временем работы от батареи и производительностью устройства. Вы можете создать несколько профилей, например "Экономия", "Сбалансированный" и "Производительность", и переключаться между ними.
Для этого нужно обновить атрибут 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 описывается батарея, в том числе ее форм-фактор, химический состав и предпочтительный производитель.
Настройки звука
Home API позволяют управлять различными настройками звука.
Включить или выключить микрофон
Чтобы включить или выключить микрофон устройства, обновите атрибут 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 |
Распознает сигналы датчиков угарного газа (CO), которые обычно представляют собой четыре коротких звуковых сигнала, за которыми следует пауза. |
Как проверить статус распознавания звуков
Чтобы показать пользователю текущее состояние распознавания звуков, необходимо проверить, что поддерживает устройство и что включено на аппаратном уровне. Проверьте следующие атрибуты:
При разработке для 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 |
Запись запускается событиями (человек, движение). Длительность видео зависит от продолжительности события и подписки. |
| ETR (запись по событию) | Etr |
Короткая запись (например, 10 секунд), которая запускается событиями. |
| Улицы в AR-режиме | 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()) }
Другие настройки
Home API позволяют управлять и другими настройками.
Измените ориентацию изображения
Ориентацию изображения (видео) с камеры можно изменить. Видео можно повернуть только на 180 градусов.
Чтобы изменить ориентацию изображения камеры, обновите атрибут imageRotation типажа CameraAvStreamManagement с помощью встроенной функции Kotlin setImageRotation:
// Change the camera's image orientation val isRotated = false cameraAvStreamManagement.update { setImageRotation(if (isRotated) 180.toUShort() else 0.toUShort()) }
Как включить или отключить ночную съемку
Чтобы включить или отключить ночное видение для камеры, используйте 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 (см. Облачный мониторинг для Home API).
Чтобы включить аналитику для устройства, задайте для свойства 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
Как вывести устройство из эксплуатации
Чтобы удалить камеру из структуры, вызовите метод device.decommissionDevice(). При выводе из эксплуатации пользователь увидит экран подтверждения от Google с предупреждением о том, что вся непрерывная видеозапись, история событий, клипы и данные библиотеки знакомых лиц будут навсегда удалены из структуры.
Подробные инструкции и примеры кода приведены в статье Как удалить устройство.