Руководство по использованию дверного звонка для Android

Тип устройства «Дверной звонок» реализован с использованием двух трейтов: PushAvStreamTransport , который обрабатывает передачу аудио- и видеопотоков с использованием протоколов на основе push-уведомлений, и WebRtcLiveView , который предоставляет возможность управления прямыми трансляциями и обратной связью.

Перед использованием каких-либо функций или попыткой обновления атрибутов всегда проверяйте поддержку атрибутов и команд для устройства. См. раздел «Управление устройствами» .Android для получения дополнительной информации.

Главная API Тип устройства Черты Пример приложения на Kotlin Вариант использования

Дверной звонок

Google Doorbell Device

home.matter.6006.types.0113

Устройство, активируемое кнопкой снаружи двери, которое подает звуковой и/или визуальный сигнал и используется для привлечения внимания человека, находящегося по другую сторону двери. Дверные звонки могут иметь доступные функции прямой трансляции, двусторонней связи или обнаружения событий.

Необходимые характеристики
google PushAvStreamTransport
google WebRtcLiveView

Дверной звонок

Получите основную информацию об устройстве.

Параметр 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

Установить разговорный язык

Установите активный язык речи на устройстве на определенный языковой стандарт (например, "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())
}

Проверьте подключение устройства.

Проверка подключения устройства фактически осуществляется на уровне типа устройства, поскольку некоторые устройства поддерживают несколько типов. Возвращаемое состояние представляет собой комбинацию состояний подключения для всех характеристик данного устройства.

val lightConnectivity = dimmableLightDevice.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()

Начать прямую трансляцию

Для запуска прямой трансляции отправьте строку протокола описания сессии (SDP) в метод startLiveView() трейта WebRtcLiveView , который вернет объект WebRtcLiveViewTrait.StartLiveViewCommand.Response , содержащий три значения:

  • План развития науки и техники для данной сессии.
  • Продолжительность сессии в секундах.
  • Идентификатор сессии, который может использоваться для продления или завершения сессии.
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)

Продлить прямую трансляцию

Прямые трансляции имеют заданную продолжительность, по истечении которой они завершаются. Чтобы продлить продолжительность активной трансляции, отправьте запрос на продление, используя метод 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
}

Запуск и остановка обратной связи

Чтобы запустить обратную связь, вызовите метод 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
    }
}

Настройки батареи

Различные параметры батареи можно контролировать через API Home.

Настройте параметры использования батареи.

Настройка баланса энергии позволяет определить оптимальное соотношение между временем автономной работы и производительностью устройства. Вы можете создавать различные профили работы батареи, такие как «Расширенный», «Сбалансированный» и «Производительный», и переключаться между ними.

Эта функция реализуется путем обновления атрибута currentEnergyBalance трейта EnergyPreference . Атрибут принимает целочисленный индекс, соответствующий определенному профилю, заданному в списке energyBalances устройства (например, 0 для EXTENDED , 1 для BALANCED и 2 для PERFORMANCE ).

Значение currentEnergyBalance null , что указывает на использование устройством пользовательского профиля. Это состояние доступно только для чтения.

Ниже приведён пример структуры, которую будет использовать атрибут 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 , а 1Enabled или 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

Настройки звука

Различные настройки звука можно контролировать с помощью 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()) }
}

Настройки зоны активности

Параметр 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), которые обычно распознаются по звуковому сигналу 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)
}

Режимы записи

Параметр RecordingMode предоставляет интерфейс для управления режимом видео- и фотозаписи на камерах и дверных звонках. Он позволяет пользователям выбирать между непрерывной записью, записью по событиям или полным отключением записи (только в режиме просмотра в реальном времени).

RecordingModeEnum определяет доступные стратегии записи:

Режим Значение перечисления Описание
Неполноценный Disabled Запись полностью отключена. Используется в основном устаревшими устройствами.
CVR (непрерывная видеозапись) Cvr Видео записывается круглосуточно. Требуется подписка (например, Google Home Premium .
EBR (Event Based Recording) Ebr Запись запускается событиями (человек, движение). Длительность видео зависит от продолжительности события и подписки.
ETR (запись, запускаемая событием) Etr Короткая предварительная запись (например, 10 секунд), запускаемая событиями.
Прямая трансляция LiveView Запись отключена, но пользователи по-прежнему могут получить доступ к прямой трансляции.
Неподвижные изображения Images Вместо видеозаписи событий записываются снимки экрана.

Проверьте режимы записи

Чтобы отобразить текущую конфигурацию записи, проверьте атрибуты трейта RecordingMode :

// 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 (см. API облачного мониторинга для Home ).

Чтобы включить аналитику для устройства, установите свойство 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 соответствует следующим значениям:

Этикетка Значение (ЮБайт)
Низкий 1u
Середина 5u
Высокий 10u

Отрегулируйте максимальную продолжительность события.

Свойство maxDuration структуры TransportMotionTriggerTimeControlStruct соответствует следующим значениям длительности (в секундах):

  • 10u , 15u , 30u , 60u , 120u , 180u

Настройки звукового сигнала

Различные настройки дверного звонка можно контролировать через API Home.

Изменить звук колокольчика

Чтобы изменить звук дверного звонка, сначала получите список установленных на устройстве звуков звонка, используя атрибут 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 , используя встроенную функцию Kotlin setSelectedChime :

// Set the chime using the chimeId from the installed list
chimeSounds.firstOrNull { it.name == name }?.let { setSelectedChime(it.chimeId) }

Используйте внешний звонок

Дверной звонок можно настроить на использование внешнего звонка, например, механического звонка, установленного внутри дома. Это следует сделать во время установки дверного звонка, чтобы избежать возможного повреждения внешнего звонка.

Чтобы указать тип установленного внешнего Chime, используйте ExternalChimeType для обновления атрибута externalChime трейта Chime с помощью встроенной функции Kotlin setExternalChime :

// Indicate the external chime is mechanical
chime.update {
  setExternalChime(ChimeTrait.ExternalChimeType.Mechanical)
}

Изменить продолжительность внешнего звукового сигнала

Продолжительность звонка внешнего звонка в секундах можно настроить через API Home. Если внешний звонок поддерживает настройку продолжительности звонка, пользователь может захотеть это сделать.

Значение, установленное здесь, зависит от технических характеристик самого внешнего звонка и рекомендуемой продолжительности его звучания.

Чтобы изменить продолжительность внешнего звукового сигнала, обновите атрибут externalChimeDurationSeconds трейта Chime , используя встроенную функцию Kotlin setExternalChimeDurationSeconds :

// Change the external chime duration
chime.update {
  setExternalChimeDurationSeconds(newDuration.toUShort())
}

Включить тему звукового сигнала

Некоторые дверные звонки могут иметь мелодии, доступные пользователям только в течение ограниченного времени. Например, мелодии, приуроченные к праздникам. Такие мелодии называются тематическими.

Чтобы узнать, какие темы оформления Chime доступны пользователю, создайте фильтр временного интервала и используйте его для фильтрации результатов команды 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)
}