门铃设备类型使用两个特征实现:PushAvStreamTransportTrait,用于使用基于推送的协议处理音频和视频流传输;WebRtcLiveViewTrait,用于提供控制直播和对讲的功能。
在尝试使用任何功能或更新属性之前,请务必先检查设备是否支持相应属性和命令。如需了解详情,请参阅控制iOS上的设备。
| Home API 设备类型 | 特征 | Swift 示例应用 | 使用场景 |
|---|---|---|---|
|
门铃
一种由门外的按钮启动的设备,可发出声音和/或视觉信号,用于引起门另一侧的人的注意。门铃可能具有无障碍直播、双向对讲或检测事件等功能。 |
必需的特征 google PushAvStreamTransportTrait google WebRtcLiveViewTrait |
门铃 |
获取有关设备的基本信息
BasicInformation 特征包含供应商名称、供应商 ID、产品 ID、产品名称(包括型号信息)、软件版本和设备的序列号等信息:
// [START get_device_information] let vendorName = basicInfoTrait.attributes.vendorName! let vendorID = basicInfoTrait.attributes.vendorID! let productID = basicInfoTrait.attributes.productID! let productName = basicInfoTrait.attributes.productName! let softwareVersion = basicInfoTrait.attributes.softwareVersion! let serialNumber = basicInfoTrait.attributes.serialNumber! // [END get_device_information]
检查设备的连接
设备的连接性实际上是在设备类型级别进行检查的,因为某些设备支持多种设备类型。返回的状态是相应设备上所有特征的连接状态的组合。
let lightConnectivity = dimmableLightDeviceType.metadata.sourceConnectivity .connectivityState
如果设备类型混杂且没有互联网连接,则可能会出现 partiallyOnline 状态。Matter 标准特征可能仍处于在线状态(由于本地路由),但基于云的特征将处于离线状态。
开始直播
如需开始直播,请将会话描述协议 (SDP) 字符串发送到 WebRtcLiveViewTrait 特征的 startLiveView(offerSdp:) 方法,该方法会返回三个值:
- 会话的 SDP。
- 会话时长(以秒为单位)。
- 会话 ID,可用于延长或终止会话。
public func sendOffer(offerSdp: String) async throws
-> (answerSdp: String, mediaSessionId: String, liveViewDuration: TimeInterval)
{
do {
// Sending StartLiveView command
let response = try await liveViewTrait.startLiveView(
offerSdp: offerSdp
)
// Received StartLiveView response
return (
answerSdp: response.answerSdp,
mediaSessionId: response.mediaSessionId,
liveViewDuration: TimeInterval(response.liveSessionDurationSeconds)
)
} catch {
// Failed to send StartLiveView command
throw error
}
}
延长直播
直播具有预设时长,超过该时长后直播会过期。如需延长有效直播的时长,请使用 extendLiveView(mediaSessionId:optionalArgsProvider:) 方法发出延期请求:
public func extendLiveView(mediaSessionId: String) async throws {
do {
// Extending live view
let extendedDuration = try await liveViewTrait.extendLiveView(mediaSessionId: mediaSessionId)
} catch {
// Failed to extend live view
throw error
}
}
启动和停止 TalkBack
如需启动 TalkBack,请调用 WebRtcLiveViewTrait 特征的 startTalkback(mediaSessionId:optionalArgsProvider:) 方法。如需停止,请使用 stopTalkback(mediaSessionId:)。
public func toggleTwoWayTalk(isOn: Bool, mediaSessionId: String) async throws {
do {
if isOn {
try await liveViewTrait.startTalkback(mediaSessionId: mediaSessionId)
} else {
try await liveViewTrait.stopTalkback(mediaSessionId: mediaSessionId)
}
} catch {
throw HomeError.commandFailed("Failed to toggle twoWayTalk: \(error)")
}
}
启用和停用录制功能
如需启用相机的录制功能,请将 TransportStatusEnum.Active 传递给 PushAvStreamTransportTrait 特征的 setTransportStatus(transportStatus:optionalArgsProvider:) 方法。如需停用录制功能,请传递 TransportStatusEnum.Inactive。
在以下示例中,我们将这些调用封装在一个使用 Boolean 切换录制功能的调用中:
public func toggleIsRecording(isOn: Bool) {
self.uiState = .loading
guard let pushAvStreamTransportTrait else {
// PushAvStreamTransportTrait not found.
return
}
Task {
do {
try await pushAvStreamTransportTrait.setTransportStatus(
transportStatus: isOn ? .active : .inactive)
if isOn {
do {
self.player = try self.createWebRtcPlayer()
} catch {
// Failed to initialize WebRtcPlayer
self.uiState = .disconnected
return
}
await self.player?.initialize()
self.uiState = .live
} else {
self.player = nil
self.uiState = .off
}
} catch {
// Failed to toggle onOff
}
}
}
启用或停用摄像头的录制功能与开启或关闭摄像头视频相同。当摄像头视频处于开启状态时,摄像头会进行录制(用于录制事件和相关片段)。
当录制功能处于停用状态(相机视频处于关闭状态)时:
- 根据设备类型的
connectivityState,摄像头仍可显示为在线。 - 无法访问实时视频画面,摄像头也未检测到任何云事件。
检查录制功能是否已启用
如需确定摄像头的录制功能是否已启用,请检查是否有任何连接处于活动状态。以下示例定义了两个函数来实现此目的:
public func isDeviceRecording() -> Bool {
guard let pushAvStreamTransportTrait else {
// PushAvStreamTransportTrait not found.
return false
}
guard
let hasActiveConnection =
pushAvStreamTransportTrait
.attributes
.currentConnections?
.contains(where: { $0.transportStatus == .active })
else {
return false
}
return hasActiveConnection
}
电池设置
您可以通过 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" } ] }
private func setBatteryUsage(to option: UInt8) async throws { _ = try await energyPreferenceTrait.update { $0.setCurrentEnergyBalance(option) } }
开启自动省电模式
如需配置此功能,请更新 EnergyPreference 特征的 currentLowPowerModeSensitivity 属性。此属性使用索引来选择敏感度级别,其中 0 通常表示 Disabled,而 1 表示 Enabled 或 Automatic。
private func setAutoBatterySaver(to value: Bool) async throws { _ = try await energyPreferenceTrait.update { $0.setCurrentLowPowerModeSensitivity(value ? 1 : 0) } }
获取电池充电状态
如需获取设备的当前充电状态(充电、充满电或未充电),请使用 PowerSource 特征的 batChargeState 属性。
self.chargingState = powerSourceTrait.attributes.batChargeState var description: String switch self.chargingState { case .isCharging: description = "Charging" case .isAtFullCharge: description = "Full" case .isNotCharging: description = "Not Charging" default: description = "Unknown" }
获取电池电量
如需获取当前电池电量,请使用 PowerSource 特征的 batChargeLevel 属性。该级别为 OK、Warning(低)或 Critical。
self.batteryLevel = powerSourceTrait.attributes.batChargeLevel var description: String switch self.batteryLevel { case .ok: description = "OK" case .warning: description = "Warning" case .critical: description = "Critical" default: description = "Unknown" }
获取电源
如需确定设备正在使用的电源,请使用 PowerSource 特征的 BatPresent 和 wiredPresent 属性。
if powerSourceTrait.attributes.wiredPresent ?? false { self.powerSourceType = .wired } else if powerSourceTrait.attributes.batPresent ?? false { self.powerSourceType = .battery } else { self.powerSourceType = nil }
音频设置
您可以通过 Home API 控制各种音频设置。
开启或关闭麦克风
如需开启或关闭设备的麦克风,请使用内置的 setMicrophoneMuted 函数更新 CameraAvStreamManagementTrait 特征的 microphoneMuted 属性:
// Turn the device's microphone on or off
func setMicrophone(on: Bool) async {
do {
_ = try await self.cameraAvStreamManagementTrait?.update {
$0.setMicrophoneMuted(!on)
}
} catch {
// Error
}
}
开启或关闭录音功能
如需开启或关闭设备的音频录制功能,请使用内置的 setRecordingMicrophoneMuted 函数更新 CameraAvStreamManagementTrait 特征的 recordingMicrophoneMuted 属性:
// Turn audio recording on or off for the device
func setAudioRecording(on: Bool) async {
do {
_ = try await self.cameraAvStreamManagementTrait?.update {
$0.setRecordingMicrophoneMuted(!on)
}
} catch {
// Error
}
}
调整音箱音量
如需调整设备的扬声器音量,请使用内置的 setSpeakerVolumeLevel 函数更新 CameraAvStreamManagementTrait 特征的 speakerVolumeLevel 属性:
// Adjust the camera speaker volume
func setSpeakerVolume(to value: UInt8) async {
do {
_ = try await cameraAvStreamManagementTrait.update {
$0.setSpeakerVolumeLevel(value)
}
} catch {
// Error
}
}
其他设置
您还可以通过 Home API 控制各种其他设置。
开启或关闭夜视功能
如需为摄像头开启或关闭夜视功能,请使用 TriStateAutoEnum 通过内置的 setNightVision 函数更新 CameraAvStreamManagementTrait 特征的 nightVision 属性:
// Turn night vision on or off
func setNightVision(
to value: Google.CameraAvStreamManagementTrait.TriStateAutoEnum
) async {
do {
_ = try await cameraAvStreamManagementTrait.update {
$0.setNightVision(value)
}
} catch {
// Error
}
}
更改状态 LED 的亮度
如需更改状态 LED 的亮度,请使用 ThreeLevelAutoEnum 通过内置的 setStatusLightBrightness 函数更新 CameraAvStreamManagementTrait 特征的 statusLightBrightness 属性:
// Set the LED brightness
func setStatusLightBrightness(
to value: Google.CameraAvStreamManagementTrait.ThreeLevelAutoEnum
) async {
do {
_ = try await cameraAvStreamManagementTrait.update {
$0.setStatusLightBrightness(value)
}
} catch {
// Error
}
}
更改相机视口
摄像头取景器与缩放和增强 Nest 摄像头视频画面支持文章中所述的“缩放和裁剪”功能相同。
视口在 ViewportStruct 中定义,其中包含四个值,这些值用作视口的坐标。坐标定义如下:
(x1,y1) -- (x2,y1) | | (x1,y2) -- (x2,y2)
确定 ViewportStruct 的值取决于应用的界面和相机实现。在最基本的层面上,如需设置相机视频的视口,请使用内置的 setViewport 函数,通过 ViewportStruct 更新 CameraAvStreamManagementTrait 特征的 viewport 属性。
func setCrop(x1: UInt16, y1: UInt16, x2: UInt16, y2: UInt16) {
let viewport = Google.CameraAvStreamManagementTrait.ViewportStruct(
x1: x1,
y1: y1,
x2: x2,
y2: y2
)
Task {
do {
try await cameraAvStreamManagementTrait.update {
$0.setViewport(viewport)
}
} catch {
// Error
}
}
}
生成 TransportOptionsStruct
某些设置需要修改 TransportOptionsStruct 中的属性,然后将其传递到流式传输连接的传输选项中。对于 Swift,需要在更新任何属性之前生成此结构。
使用此辅助函数生成结构,以用于以下设置更改:
func getTransportOptions(
transportOptions: Google.PushAvStreamTransportTrait.TransportOptionsStruct,
wakeUpSensitivity: UInt8?,
maxEventLength: UInt32?
) async throws
-> Google.PushAvStreamTransportTrait.TransportOptionsStruct
{
var newMotionTimeControl:
Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct? = nil
if let maxEventLength {
guard let motionTimeControl = transportOptions.triggerOptions.motionTimeControl else {
throw HomeError.failedPrecondition(
// Error - cannot update max event length without motion time control
}
newMotionTimeControl =
Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct(
initialDuration: motionTimeControl.initialDuration,
augmentationDuration: motionTimeControl.augmentationDuration,
maxDuration: maxEventLength,
blindDuration: motionTimeControl.blindDuration
)
}
return Google.PushAvStreamTransportTrait.TransportOptionsStruct(
streamUsage: .recording,
videoStreamID: nil,
audioStreamID: nil,
tlsEndpointID: transportOptions.tlsEndpointID,
url: transportOptions.url,
triggerOptions: Google.PushAvStreamTransportTrait.TransportTriggerOptionsStruct(
triggerType: .motion,
motionZones: nil,
motionSensitivity: wakeUpSensitivity,
motionTimeControl: newMotionTimeControl,
maxPreRollLen: nil
),
ingestMethod: .cmafIngest,
containerOptions: Google.PushAvStreamTransportTrait.ContainerOptionsStruct(
containerType: .cmaf,
cmafContainerOptions: nil
),
expiryTime: nil
)
}
private func getRecordingConnection() async throws
-> Google.PushAvStreamTransportTrait.TransportConfigurationStruct?
{
guard let pushAvStreamTransportTrait else {
// Error - PushAvStreamTransport trait not available
return nil
}
let connections = try await pushAvStreamTransportTrait.findTransport().transportConfigurations
for connection in connections {
guard let transportOptions = connection.transportOptions,
transportOptions.streamUsage == .recording
else {
continue
}
return connection
}
return nil
}
调整设备唤醒灵敏度
设备的唤醒灵敏度用于通过以下方式节省电池电量:缩短设备可感应活动的范围,以及在检测到活动后延长唤醒时间。
在 Home API 中,可以使用设备 transportOptions 中 triggerOptions 的 motionSensitivity 属性来设置此值。这些选项是在每个设备的 PushAvStreamTransportTrait 特征中定义的。
唤醒灵敏度只能设置为以下值:
- 1 = 低
- 5 = 中等
- 10 = 高
更新过程如下:使用 findTransport 命令查找有效录制流的传输配置,然后使用 modifyPushTransport 命令修改配置,使其包含新的灵敏度值。
modifyPushTransport 命令需要传递完整的 TransportOptionsStruct,因此您必须先从当前配置中复制现有值。请参阅为执行此操作的辅助函数生成 TransportOptionsStruct。
func setWakeUpSensitivity(to value: UInt8) async {
do {
let connection = try await getRecordingConnection()
guard let connection,
let transportOptions = connection.transportOptions
else {
// Error - Transport options not available
return
}
guard transportOptions.triggerOptions.motionSensitivity != nil else {
// Error - Motion sensitivity not available to be updated for this device
return
}
try await pushAvStreamTransportTrait.modifyPushTransport(
connectionID: connection.connectionID,
transportOptions: self.getTransportOptions(
transportOptions: transportOptions,
wakeUpSensitivity: value,
maxEventLength: nil
)
)
} catch {
// Error
}
}
调整事件录制时长上限
事件时长上限是指摄像头为事件录制片段的时长。通过 Home API,您可以按设备将此参数配置为与通过 Google Home app (GHA) 配置的长度相同的长度(以秒为单位):
- 10 秒
- 15 秒
- 30 秒
- 60 秒(1 分钟)
- 120 秒(2 分钟)
- 180 秒(3 分钟)
在 Home API 中,可以使用设备 transportOptions 中 triggerOptions 的 motionTimeControl 属性来设置此值。这些选项是在每个设备的 PushAvStreamTransportTrait 特征中定义的。
更新过程如下:使用 findTransport 命令查找有效录制流的传输配置,然后使用 modifyPushTransport 命令修改配置,使其包含新的活动时长值。
modifyPushTransport 命令需要传递完整的 TransportOptionsStruct,因此您必须先从当前配置中复制现有值。请参阅为执行此操作的辅助函数生成 TransportOptionsStruct。
func setMaxEventLength(to value: UInt32) async {
do {
let connection = try await getRecordingConnection()
guard let connection,
let transportOptions = connection.transportOptions
else {
// Error - Transport options not available
return
}
guard transportOptions.triggerOptions.motionTimeControl != nil else {
// Error - Motion time control not available to be updated for this device
return
}
try await pushAvStreamTransportTrait.modifyPushTransport(
connectionID: connection.connectionID,
transportOptions: self.getTransportOptions(
transportOptions: transportOptions,
wakeUpSensitivity: nil,
maxEventLength: value
)
)
} catch {
// Error
}
}
电铃设置
您可以通过 Home API 控制各种门铃铃声设置。
更改电铃声音
如需更改门铃响铃声音,请先使用 ChimeTrait 特征的 installedChimeSounds 属性获取设备上安装的响铃声音列表:
doorbellChimeTrait.attributes.installedChimeSounds?.compactMap { chimeSound in
return chimeSound.chimeID, chimeSound.name
}
然后,使用内置的 setSelectedChime 函数更新 ChimeTrait 特征的 selectedChime 属性:
func setDoorbellChime(chimeID: UInt8) async {
do {
_ = try await doorbellChimeTrait.update {
$0.setSelectedChime(chimeID)
}
} catch {
// Error
}
}
使用外部门铃
您可以将门铃配置为使用外部铃声,例如安装在住宅内的机械铃。应在安装门铃时配置此设置,以避免可能损坏外部门铃。
如需指明安装的外部门铃类型,请使用 ExternalChimeType 通过内置的 setExternalChime 函数更新 ChimeTrait 特征的 externalChime 属性:
// Indicate the external chime is mechanical
func setExternalChime(to value: Google.ChimeTrait.ExternalChimeType) async {
do {
_ = try await doorbellChimeTrait.update {
$0.setExternalChime(value)
}
} catch {
// Error
}
}
更改外部电铃时长
外部门铃响铃的时长(以秒为单位)可通过 Home API 进行配置。如果外部铃声支持铃声时长,用户可能需要配置此设置。
此处设置的值取决于外部门铃本身的规格及其建议的门铃时长。
如需更改外部响铃时长,请使用内置的 setExternalChimeDurationSeconds 函数更新 ChimeTrait 特征的 externalChimeDurationSeconds 属性:
// Change the external chime duration
func setExternalChimeDuration(to value: UInt16) async {
do {
_ = try await doorbellChimeTrait.update {
$0.setExternalChimeDuration(value)
}
} catch {
// Error
}
}
启用铃声主题
部分门铃可能提供仅限时向用户提供的铃声。例如,特定于节假日的铃声。 这些主题称为铃声主题。
如需查看用户可用的铃声主题,请创建时间箱过滤条件,并使用该过滤条件过滤 ChimeThemes 特征的 getAvailableThemes 命令的结果。此方法会返回可用主题的列表,包括主题名称。
以下示例展示了如何过滤列表。
如果当前时间在主题的开始时间和结束时间(分别为 startTimeSeconds 和 endTimeSeconds 值)范围内,则该主题被视为有效。如果未设置开始时间,则视为从一开始就处于有效状态。如果未设置结束时间,则会无限期保持有效状态。如果两者均缺失,则主题始终处于有效状态。
let chimeThemes = try await chimeThemeTrait.getAvailableThemes().themes
if !chimeThemes.isEmpty {
var chimeThemeSettings = []
for chimeTheme in chimeThemes {
let currentDateTime = UInt64(Date().timeIntervalSince1970)
// Only show chime themes that are active.
if chimeTheme.startTimeSeconds ?? 0 <= currentDateTime
&& chimeTheme.endTimeSeconds ?? UInt64.max >= currentDateTime
{
self.chimeThemeSettings.append(chimeTheme.name)
}
}
}
获得所需主题的名称(例如 Christmas)后,您可以使用 ChimeThemes ChimeThemes 特征的 setSelectedTimeboxedThemeName() 函数来选择该主题。
private func setChimeTheme(to value: String) async throws {
_ = try await chimeThemeTrait.update {
$0.setSelectedTimeboxedThemeName(value)
}
}```