门铃设备类型使用以下三个特征实现:PushAvStreamTransport,使用基于推送的协议处理音频和视频流传输;WebRtcLiveView,提供控制直播和对讲的功能;CameraSnapshot,提供缓存的预览快照和实时快照捕获。
在使用任何功能或尝试更新属性之前,请务必检查设备是否支持相应属性和命令。如需了解详情,请参阅在Android上控制设备。
| Home API 设备类型 | 特征 | Kotlin 示例应用 | 使用场景 |
|---|---|---|---|
|
门铃
一种由门外按钮启动的设备,可发出声音和/或视觉信号,用于引起门内某人的注意。门铃可能具有可访问的直播、双向对讲或检测事件。 |
必需的特征 google PushAvStreamTransport google WebRtcLiveView |
门铃 |
获取设备的基本信息
BasicInformation 特征包含供应商名称、供应商 ID、产品 ID、商品名称(包含型号信息)和设备软件版本等信息:
// 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}") }
获取序列号
如需获取设备的序列号,请使用 ExtendedBasicInformation trait 的 GetSerialNumber 命令。
以下示例展示了如何将序列号保存在名为 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}")
}
}
设置讲话语言
使用 LocalizationConfiguration trait 的 setActiveLocale 方法将设备的活跃口语设置为特定语言区域(例如“en_US”)。
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) }
获取设备最近一次与云端联系的时间
如需查找设备最近一次与云端联系的时间,请使用 ExtendedGeneralDiagnostics 特性的 lastContactTimestamp 属性:
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) }
检查设备的连接情况
设备的连接性实际上是在设备类型级别进行检查的,因为某些设备支持多种设备类型。返回的状态是该设备上所有特征的连接状态的组合。
在 Android 示例应用中实现val doorbellConnectivity = doorbellDevice.metadata.sourceConnectivity.connectivityState
在没有互联网连接的情况下,如果设备类型混合,可能会观察到 PARTIALLY_ONLINE 状态。由于本地路由,Matter 标准特性可能仍处于在线状态,但基于云的特性将处于离线状态。
获取设备的 IP 地址
如需查找设备的 IP 地址,请使用 GeneralDiagnostics 特性的 networkInterfaces 属性。这些地址会以字节数组的形式返回,您可以将其格式化为标准的 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) 字符串发送到 WebRtcLiveView 特性的 startLiveView() 方法,该方法会返回一个包含三个值的 WebRtcLiveViewTrait.StartLiveViewCommand.Response:
- 会话的 SDP。
- 会话时长(以秒为单位)。
- 会话 ID,可用于延长或终止会话。
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 }
启动和停止 TalkBack
如需启动对讲,请调用 WebRtcLiveView 特性的 startTalkback() 方法。如需停止,请使用 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 传递给 PushAvStreamTransport 特性的 setTransportStatus() 方法。如需停用录制功能,请向其传递 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 } }
检索摄像头快照
使用 CameraSnapshot 特性可从摄像头检索静态图片快照。
这些快照适用于以下几种场景:
CameraSnapshot 特性提供了两种提取快照的方法,具体取决于您是需要缓存的快照以实现快速渲染,还是需要按需实时快照。
获取缓存的预览快照
预览快照是 SDK 无需唤醒摄像头即可检索的缓存图片。这是获取静态图片的最快方法,非常适合摄像头概览页面或信息中心网格。
如需获取预览快照,请读取 preview_image_url trait 属性:
// 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 }
根据摄像头配置和活动,预览网址会指向根据近期视频片段(最新视频片段的第一个 I 帧)生成的缓存图片,或摄像头定期上传的快照。
为了指明图片的新鲜度,Google Home 云会在提供的 JPEG/PNG 图片中嵌入一个 X-Home-Image-Captured-At 标头,格式为世界协调时间 (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}") }
对快照请求进行身份验证
所有快照网址都指向安全媒体,并且需要 Home API v2 范围的 OAuth 2.0 令牌。如需下载和呈现图片,必须将 OAuth 令牌作为不记名令牌注入到 HTTP 请求的 Authorization 标头中。
以下示例演示了如何配置安全网络请求以下载快照:
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 特性动态更改画质,可专门管理特定客户端上活跃直播会话的分辨率。这与直接在设备上配置设备级带宽用量设置不同,后者会影响所有并发观看者以及保存到云端的历史视频录制内容的质量。
以下示例演示了如何检索和更新设备的直播画质:
检索支持的画质选项:获取设备支持的可用在线播放分辨率。该代码会查询设备类型 flow 上的
WebRtcLiveViewtrait 的supportedQualityHints属性,并将支持的画质公开为包含QualityHint值(例如QUALITY_HINT_SD、QUALITY_HINT_HD、QUALITY_HINT_FHD、QUALITY_HINT_QHD或QUALITY_HINT_UHD)的StateFlow。更改直播画质:应用所选的
QualityHint,以更改当前直播的流式传输分辨率(例如,从标清切换到高清)。changeQuality函数会解析设备的直播特征,并使用有效的mediaSessionId和所选的QualityHint配置调用changeLiveViewQuality。
// 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 } }
电池设置
您可以通过 Home API 控制各种电池设置。
设置电池用量偏好
通过设置能耗平衡,您可以配置设备的电池续航时间与性能之间的权衡。您可以创建不同的电池配置文件,例如“延长”“平衡”和“性能”,并在它们之间切换。
此功能通过更新 EnergyPreference 特性的 currentEnergyBalance 属性来实现。该属性接受与设备 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)
开启自动省电模式
如需配置此功能,请更新 EnergyPreference trait 的 currentLowPowerModeSensitivity 属性。此属性使用索引来选择敏感度级别,其中 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) } }
获取电池充电状态
如需获取设备的当前充电状态(正在充电、已充满电或未充电),请使用 PowerSource 特性的 batChargeState 属性。
// 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" }
获取电池电量
如需获取当前电池电量,请使用 PowerSource 特性的 batChargeLevel 属性。级别为 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" }
获取电源
如需确定设备使用的电源,请使用 PowerSource 特性的 BatPresent 和 wiredPresent 属性。
val trait: PowerSource val isWired = trait.wiredPresent val hasBattery = trait.batPresent
检查电池是否需要更换
batReplaceability 属性用于指明电池是不可更换、可由用户更换还是可由工厂更换。
PowerSource 特性的 batReplacementNeeded 属性会告知您是否需要更换电池。
// Get the battery replacement status val batteryStatus = powerSourceTrait.batReplacementNeeded if (batteryStatus) { println("Replace the battery.") }
如果电池可由用户更换,batReplacementDescription 会描述电池,包括外形规格、化学成分和首选制造商等信息。
音频设置
您可以通过 Home API 控制各种音频设置。
开启或关闭麦克风
如需开启或关闭设备的麦克风,请使用内置的 setMicrophoneMuted Kotlin 函数更新 CameraAvStreamManagement 特性的 microphoneMuted 属性:
// Turn the device's microphone on or off suspend fun turnOffMicrophone(disableMicrophone: Boolean, trait: CameraAvStreamManagement) { trait.update { setMicrophoneMuted(disableMicrophone) } }
开启或关闭录音设置
如要为设备开启或关闭录音功能,请使用内置的 setRecordingMicrophoneMuted Kotlin 函数更新 CameraAvStreamManagement trait 的 recordingMicrophoneMuted 属性:
// Turn audio recording on or off for the device suspend fun turnOffAudioRecording(disableAudioRecording: Boolean, trait: CameraAvStreamManagement) { trait.update { setRecordingMicrophoneMuted(disableAudioRecording) } }
调节音箱音量
如需调整设备的音箱音量,请使用内置的 setSpeakerVolumeLevel Kotlin 函数更新 CameraAvStreamManagement 特性的 speakerVolumeLevel 属性:
// Adjust the camera speaker volume suspend fun adjustSpeakerVolume(volume: Int, trait: CameraAvStreamManagement) { trait.update { setSpeakerVolumeLevel(volume.toUbyte()) } }
活动所涉区域设置
ZoneManagement 特性提供了一个接口,用于管理摄像头和门铃设备上的自定义关注区域(活动所涉区域)。这些区域用于将事件检测(例如人员或车辆移动)过滤到设备视野范围内的特定区域。
活动所涉区域由用户在合作伙伴应用中配置,允许用户在摄像头视野范围内的特定区域绘制区域。然后,这些用户定义的区域会转换为此 trait 使用的结构。 如需详细了解活动所涉区域的运作方式,请参阅设置和使用活动所涉区域。
活动所涉区域通常使用二维笛卡尔坐标来定义。该 trait 为顶点提供 TwoDCartesianVertexStruct,为区域定义(名称、顶点、颜色和用法)提供 TwoDCartesianZoneStruct。
检查活动所涉区域
如需显示活动所涉区域,请检查 ZoneManagement trait 的 zones 属性。
// 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,用于定义区域的名称、顶点、颜色和用途。
以下示例展示了如何创建一个名为“Front Porch”的区域,该区域有四个顶点,颜色为鲑鱼色 (#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 Flow 时,您通常会观察 HomeDevice 中的 AvStreamAnalysis 特性。
// 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(事件录像) | 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(), ) } }
更改录制模式
在更新之前,请确保 availableRecordingModes 属性中存在从 supportedRecordingModes 属性中选择的索引。
如需更新所选模式,请使用 setSelectedRecordingMode 函数,并传入所选模式的索引:
private suspend fun RecordingMode.updateRecordingMode(index: Int) { // Execute the command to update the selected mode this.setSelectedRecordingMode(index.toUByte()) }
其他设置
您可以通过 Home API 控制各种其他设置。
开启或关闭夜视功能
如需为摄像头开启或关闭夜视功能,请使用 TriStateAutoEnum,通过内置的 setNightVision Kotlin 函数更新 CameraAvStreamManagement 特性的 nightVision 属性:
// Turn night vision on cameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.On) } // Turn night vision off CameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.Off) }
更改状态 LED 的亮度
如需更改状态 LED 的亮度,请使用 ThreeLevelAutoEnum 通过内置 setStatusLightBrightness Kotlin 函数更新 CameraAvStreamManagement 特性的 statusLightBrightness 属性:
// 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 的值取决于应用的界面和相机实现。在最基本的层面上,如需设置相机视频的视口,请使用内置的 setViewport Kotlin 函数,通过 ViewportStruct 更新 CameraAvStreamManagement 特性的 viewport 属性:
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 API)。
如需为设备启用分析功能,请将 ExtendedGeneralDiagnosticsTrait 的 analyticsEnabled 属性设置为 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 ) }
确定带宽质量
TransportOptionsStruct 的 videoStreamId 属性对应于特定的视频流配置。
如需获取支持的视频流,请参阅 allocatedVideoStreams 属性,该属性是 VideoStreamStructs 的列表。从设备的 CameraAvStreamManagement 特性中获取。
调整设备唤醒灵敏度
TransportTriggerOptionsStruct 的 motionSensitivity 属性对应于以下值:
| 标签 | 值 (UByte) |
|---|---|
| 低 | 1u |
| 中 | 5u |
| 高 | 10u |
调整事件时长上限
TransportMotionTriggerTimeControlStruct 的 maxDuration 属性对应于以下时长(以秒为单位):
- 10u、15u、30u、60u、120u、180u
电铃设置
您可以通过 Home API 控制各种门铃响铃设置。
更改提示音
如需更改门铃提示音,请先使用 Chime trait 的 installedChimeSounds 属性获取设备上安装的提示音列表:
// 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()
然后,使用内置的 setSelectedChime Kotlin 函数更新 Chime 特性的 selectedChime 属性:
// Set the chime using the chimeId from the installed list chimeSounds.firstOrNull { it.name == name }?.let { setSelectedChime(it.chimeId) }
使用外接电铃
门铃可以配置为使用外部铃声,例如安装在住宅内的机械铃。此设置应在门铃安装期间进行配置,以免对外部电铃造成潜在损坏。
如需指明安装的外部铃声类型,请使用 ExternalChimeType,通过内置的 setExternalChime Kotlin 函数更新 Chime 特性的 externalChime 属性:
// Indicate the external chime is mechanical chime.update { setExternalChime(ChimeTrait.ExternalChimeType.Mechanical) }
更改外接电铃时长
您可以通过 Home API 配置外部响铃的持续时间(以秒为单位)。如果外部响铃支持响铃时长,用户可能需要配置此设置。
此处设置的值取决于外部电铃本身的规格,以及其建议的响铃时长。
如需更改外部响铃时长,请使用内置的 setExternalChimeDurationSeconds Kotlin 函数更新 Chime 特性的 externalChimeDurationSeconds 属性:
// Change the external chime duration chime.update { setExternalChimeDurationSeconds(newDuration.toUShort()) }
启用提示音主题
某些门铃可能具有仅在限定时间内供用户使用的铃声。例如,节假日专属提示音。 这些称为提示音主题。
如需查看用户可以使用哪些提示音主题,请创建一个时间盒过滤器,并使用它来过滤 ChimeThemes 特性的 getAvailableThemes() 命令的结果。这将返回可用主题列表,包括主题名称。
以下示例展示了如何过滤列表。
如果当前时间在主题的开始时间和结束时间(分别为 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)后,您可以使用 ChimeThemes 特征上的 setSelectedTimeboxedThemeName() 函数来选择该主题:
// Select a theme using the ChimeThemes trait val themeToSelect = "Christmas" if (themeToSelect in availableThemeNames) { doorbellChimeThemesTraitFlow.first().setSelectedTimeboxedThemeName(themeToSelect) }
来访者通知设置
您可以使用 Home API 的 VisitorAnnouncement trait 查询和管理门铃的来访者通知设置。此 trait 用于控制当有人按门铃时,是否在 Google 智能音箱或显示屏上播报访客到访。
以下示例展示了如何检查是否已启用访客通知,以及如何更新此设置:
// Read the current visitor announcements state val isEnabled = visitorAnnouncementTrait.visitorAnnouncementsEnabled // Toggle the visitor announcements setting visitorAnnouncementTrait.update { setVisitorAnnouncementsEnabled(true) }
停用设备
如需从结构中移除门铃,请调用 device.decommissionDevice()。停用时,系统会向用户显示一个由 Google 管理的确认界面,警告用户所有已录制的全天候视频历史记录、事件记录、片段和熟面孔库数据都将从结构中永久删除。
如需查看详细说明和代码示例,请参阅移除设备。