iOS 攝影機裝置指南

攝影機裝置類型是透過兩種特徵實作: PushAvStreamTransportTrait,可使用以推送為基礎的通訊協定處理音訊和影片串流傳輸;以及 WebRtcLiveViewTrait,可控制即時串流和對講功能。

使用任何功能或嘗試更新屬性之前,請務必先檢查裝置是否支援屬性和指令。詳情請參閱「透過iOS 控制裝置」。

Home API 裝置類型 特徵 Swift 範例應用程式 用途

相機

GoogleCameraDeviceType

home.matter.6006.types.0158

可拍攝靜態圖片或影片的裝置。攝影機可能提供無障礙即時串流、雙向通話或偵測事件。

必要特徵
     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!
// [END get_device_information]

取得序號

如要取得裝置序號,請使用 ExtendedBasicInformation 特徵的 GetSerialNumber 指令。這個範例顯示如何將序號儲存在名為 serialNumber 的變數中:

// Assuming extendedBasicInformationTrait: Google.ExtendedBasicInformationTrait
let response = try await extendedBasicInformationTrait.getSerialNumber()
let serialNumber = response.serialNumber

取得裝置與雲端連線的最新時間

如要找出裝置最近一次與雲端連線的時間,請使用 ExtendedGeneralDiagnostics 特徵的 lastContactTimestamp 屬性:

if let lastContactTimeStamp = extendedGeneralDiagnosticsTrait.attributes.lastContactTimestamp {
  self.lastContactTime = Date(timeIntervalSince1970: Double(lastConnectedTimeStamp))
}

檢查裝置的連線狀態

裝置的連線狀態實際上是在裝置類型層級檢查,因為部分裝置支援多種裝置類型。傳回的狀態是該裝置上所有特徵的連線狀態組合。

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

如果沒有網際網路連線,混合裝置類型可能會顯示 partiallyOnline 狀態。Matter標準特徵可能仍會因本機路由而保持連線,但雲端特徵會離線。

取得裝置的 IP 位址

如要找出裝置的 IP 位址,請使用 GeneralDiagnosticsTraitnetworkInterfaces 屬性。位址會以 Data 物件的形式傳回,您可以使用 Network 架構將位址格式化為標準 IPv4 或 IPv6 字串:

func getIpAddresses(trait: Matter.GeneralDiagnosticsTrait) -> [String] {
  let interfaces = trait.attributes.networkInterfaces ?? []
  var ipAddresses: [String] = []

  for interface in interfaces {
    for data in interface.iPv4Addresses {
      if let ipv4 = IPv4Address(data) {
        ipAddresses.append(String(describing: ipv4))
      }
    }
    for data in interface.iPv6Addresses {
      if let ipv6 = IPv6Address(data) {
        ipAddresses.append(String(describing: ipv6))
      }
    }
  }

  return ipAddresses
}

開始直播

如要開始直播,請將工作階段描述通訊協定 (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
    }
  }
}

啟用或停用攝影機的錄影功能,等同於開啟或關閉攝影機影像。攝影機影像開啟時,攝影機就會錄影 (用於事件和相關影像片段)。

錄製功能停用時 (攝影機影片關閉):

確認是否已啟用錄製功能

如要判斷攝影機是否已啟用錄影功能,請檢查是否有任何連線處於啟用狀態。以下範例定義了兩個函式來執行這項操作:

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 清單中定義的特定設定檔對應的整數索引 (例如 EXTENDED0BALANCED1,以及 PERFORMANCE2)。

currentEnergyBalancenull 值表示裝置使用自訂設定檔。這是唯讀狀態。

以下範例顯示 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 代表 EnabledAutomatic

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 屬性。層級可以是 OKWarning (低) 或 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 特徵的 BatPresentwiredPresent 屬性。

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
  }
}

活動區設定

ZoneManagement 特徵提供介面,可管理攝影機和門鈴裝置上的自訂感興趣區域 (活動區)。這些區域可用於篩選裝置視野內特定區域的事件偵測結果 (例如人物或車輛移動)。

使用者可在合作夥伴應用程式中設定活動區,在攝影機視野的特定區域繪製活動區。這些使用者定義的區域隨後會轉換為這個特徵所用的結構。如要進一步瞭解活動區的運作方式,請參閱「設定及使用活動區」一文。

活動區通常是使用 2D 直角座標定義。 這個特徵提供頂點的 TwoDCartesianVertexStruct,以及區域定義 (名稱、頂點、顏色和用途) 的 TwoDCartesianZoneStruct

查看活動區

如要顯示活動區,請檢查 ZoneManagement 特徵的 zones 屬性。

let zoneManagementTrait: Google.ZoneManagementTrait

self.zones = zoneManagementTrait.attributes.zones ?? []

新增活動區

如要建立新區域,請使用 createTwoDCartesianZone 指令。這項指令會採用 TwoDCartesianZoneStruct,定義區域的名稱、頂點、顏色和用途。

以下範例說明如何建立名為「前廊」的區域,其中包含四個頂點,顏色為鮭魚色 (#F439A0),並用於動作偵測。

import GoogleHomeSDK
import GoogleHomeTypes

func createFrontPorchZone(trait: Google.ZoneManagementTrait) async {
  // 1. Define the vertices for the zone (2D Cartesian coordinates)
  // Values are UInt16, typically scaled to the device's twoDCartesianMax.
  let vertices = [
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 260, y = 422),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1049, y = 0),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048, y = 0),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048, y = 950),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1630, y = 1349),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 880, y = 2048),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 0, y = 2048),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 638, y = 1090)
  ]

  // 2. Define the zone structure using the given SDK struct
  let newZone = Google.ZoneManagementTrait.TwoDCartesianZoneStruct(
    name: "Front Porch",
    use: [.motion], // ZoneUseEnum.motion
    vertices: vertices,
    // Color is a hex string (for example, Salmon/Pink)
    color: "#F439A0"
  )

  do {
    // 3. Execute the raw command to add the zone to the device
    // This returns the created zone's ID (UInt16).
    var newZoneID = try await trait.createTwoDCartesianZone(zone: newZone)
  } catch {
    // Error
  }
}

更新活動區

如要更新現有區域,請使用 updateTwoDCartesianZone 指令。這項指令需要 zoneId 和更新後的 TwoDCartesianZoneStruct

let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16
let zone: Google.ZoneManagementTrait.TwoDCartesianZoneStruct

do {
  _ = try await zoneManagementTrait.updateTwoDCartesianZone(
        zoneID: zoneID, zone: zone)
} catch {
  // Error
}

刪除活動區

如要移除區域,請使用 removeZone 指令搭配特定 zoneId

let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16

do {
  _ = try await zoneManagementTrait.removeZone(zoneID: zoneID)
} catch {
  // Error
}

聲響偵測事件觸發條件

AvStreamAnalysis 特徵提供介面,可管理攝影機和門鈴裝置的事件偵測觸發條件。以影像為準的觸發條件 (例如人或車輛) 可指定區域,但聲音相關的觸發條件通常是裝置層級的設定。

使用 EventTriggerTypeEnum 進行聲響偵測時,可用的觸發條件類型如下:

模式 列舉值 說明
音效 Sound 一般聲響偵測。
有人說話 PersonTalking 偵測語音。
狗吠聲 DogBark 偵測犬隻的叫聲。
玻璃碎裂 GlassBreak 偵測玻璃破裂聲。
煙霧警報 SmokeAlarm 偵測煙霧警報器,通常會辨識 T3 可聽見的模式 (三聲短促的嗶聲,然後暫停)。
一氧化碳警報 CoAlarm 偵測一氧化碳警報,通常會以 T4 聲音模式 (四聲短促的嗶聲,接著暫停) 辨識。

查看聲響偵測狀態

如要向使用者顯示聲響偵測的目前狀態,請務必檢查裝置支援的項目,以及裝置硬體啟用的項目。要檢查的屬性有兩個:

在 iOS 開發中,您通常會從裝置存取 AvStreamAnalysis 特徵,以讀取這些屬性。

// Example struct to store event triggers
public struct EventTrigger: Equatable {
  public var id: Google.AvStreamAnalysisTrait.EventTriggerTypeEnum
  public var enabled: Bool
}

let avStreamAnalysisTrait: Google.AvStreamAnalysisTrait

let possibleEventTriggers = avStreamAnalysisTrait.attributes.supportedEventTriggers ?? []
let enabledEventTriggers = avStreamAnalysisTrait.attributes.enabledEventTriggers ?? []

let eventTriggers [EventTrigger] = []
for trigger in possibleEventTriggers {
  self.eventTriggers.append(
    EventTrigger(
      id: trigger,
      enabled: enabledEventTriggers.contains(trigger)
    )
  )
}

更新已啟用觸發條件的集合

如要更新已啟用觸發條件的集合,請使用 SetOrUpdateEventDetectionTriggers 指令,該指令會採用 EventTriggerEnablement 結構清單。

// Example struct to store event triggers
public struct EventTrigger: Equatable {
  public var id: Google.AvStreamAnalysisTrait.EventTriggerTypeEnum
  public var enabled: Bool
}

let avStreamAnalysisTrait: Google.AvStreamAnalysisTrait
let eventTriggers: [EventTrigger]

let enabledEventTriggers = eventTriggers.map {
  Google.AvStreamAnalysisTrait.EventTriggerEnablement(
    eventTriggerType: $0.id,
    enablementStatus: $0.enabled ? .enabled : .disabled
  )
}

try await avStreamAnalysisTrait.setOrUpdateEventDetectionTriggers(
  eventTriggerEnablements: enabledEventTriggers
)

錄製模式

RecordingMode 特徵提供介面,可管理攝影機和門鈴裝置的影片和圖片錄製行為。使用者可以選擇連續錄影、事件錄影,或完全停用錄影功能 (僅限即時監控)。

RecordingModeEnum 定義可用的記錄策略:

模式 列舉值 說明
已停用 Disabled 錄製功能已完全停用。主要用於舊版裝置。
CVR (連續錄影) Cvr 攝影機全天候錄影。須訂閱 (例如 Google Home Premium)。
事件錄影 Ebr 錄影功能會在偵測到人員或動作時啟動。 影片長度取決於活動時間長度和訂閱方案。
ETR (事件觸發錄影) Etr 事件觸發的短時間預錄內容 (例如 10 秒)。
實景 LiveView 錄製功能已停用,但使用者仍可觀看直播。
靜態圖片 Images 發生事件時,系統會錄製快照,而非影片。

檢查錄製模式

如要顯示目前的錄製設定,請檢查 RecordingMode 特徵的屬性:

// Example struct to store recording modes.
public struct RecordingMode: Hashable {
  public let id: UInt8
  public let mode: Google.RecordingModeTrait.RecordingModeEnum
}

let recordingModeTrait: Google.RecordingModeTrait

if let availableRecordingModes = recordingModeTrait.attributes.availableRecordingModes,
   let supportedRecordingModes = recordingModeTrait.attributes.supportedRecordingModes,
   let selectedRecordingMode = recordingModeTrait.attributes.selectedRecordingMode {

  var recordingModes: [RecordingMode] = []

  for recordingModeId in availableRecordingModes {
    guard Int(recordingModeId) < supportedRecordingModes.count,
          Int(recordingModeId) >= 0 else {
      // Out of bounds error
    }

    recordingModes.append(
      RecordingMode(
        id: recordingModeId,
        mode: supportedRecordingModes[Int(recordingModeId)].recordingMode,
      )
    )
  }
}

變更錄製模式

更新前,請確認 supportedRecordingModes 屬性中選擇的索引位於 availableRecordingModes 屬性中。

如要更新所選模式,請使用 setSelectedRecordingMode 函式,並傳遞所選模式的索引:

let recordingModeTrait: Google.RecordingModeTrait
let recordingModeID: UInt8

_ = try await recordingModeTrait.update {
  $0.setSelectedRecordingMode(recordingModeID)
}

其他設定

您也可以透過 Home API 控制其他設定。

變更圖片方向

你可以旋轉攝影機影像 (影片) 的方向,影片只能旋轉 180 度。

如要變更攝影機的影像方向,請使用內建的 setImageRotation 函式,更新 CameraAvStreamManagementTrait 特徵的 imageRotation 屬性:

// Change the camera's image orientation
// Value must be 0 or 180
func setImageRotation(to value: UInt16) async {
  do {
    _ = try await cameraAvStreamManagementTrait.update {
      $0.setImageRotation(value)
    }
  } catch {
    // Error
  }
}

開啟或關閉夜視模式

如要開啟或關閉攝影機的夜視功能,請使用 TriStateAutoEnum 更新 CameraAvStreamManagementTrait 特徵的 nightVision 屬性,方法是使用內建的 setNightVision 函式:

// 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 更新 statusLightBrightness CameraAvStreamManagementTrait 特徵的屬性,方法是使用內建的 setStatusLightBrightness 函式:

// 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 的值取決於應用程式的 UI 和相機實作方式。在最基本的層級,如要設定攝影機影片的檢視區塊,請使用內建的 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
}

啟用或停用數據分析

每部裝置都可以個別選擇將詳細的數據分析資料傳送至 Google Home 雲端 (請參閱「適用於 Home API 的 Cloud Monitoring」)。

如要為裝置啟用數據分析功能,請將 ExtendedGeneralDiagnosticsTraitanalyticsEnabled 屬性設為 true。當您設定 analyticsEnabled 時,系統會自動將另一個屬性 logUploadEnabled 設為 true,以便將分析記錄檔上傳至 Google Home 雲端。

// Enable analytics
_ = try await extendedGeneralDiagnosticsTrait.update {
  $0.setAnalyticsEnabled(true)
}

// Disable analytics
_ = try await extendedGeneralDiagnosticsTrait.update {
  $0.setAnalyticsEnabled(false)
}

傳輸和錄製設定

本節說明攝影機串流品質和事件觸發相關設定。這些設定由 PushAvStreamTransport 特徵管理。

讀取傳輸設定

本節說明如何從攝影機或門鈴裝置擷取目前的設定。這項功能會擷取 PushAvStreamTransport 特徵、找出用於錄製的特定連線,然後擷取頻寬品質、喚醒靈敏度和最長事件長度的目前值。

// Assuming access to
// var pushAvStreamTransportTrait: Google.PushAvStreamTransportTrait
let connections = try await pushAvStreamTransportTrait.findTransport().transportConfigurations

// Locate the connection designated for recording
let recordingConnection = connections.first { connection in
    guard let transportOptions = connection.transportOptions else { return false }
    return transportOptions.streamUsage == .recording
}

let options = recordingConnection?.transportOptions

// 1. Bandwidth Quality (Video Stream ID)
let videoStreamId = options?.videoStreamID

// 2. Wake-up Sensitivity (Motion Sensitivity)
let wakeUpSensitivity = options?.triggerOptions.motionSensitivity

// 3. Max Event Length (Motion Trigger Time Control)
let maxEventLength = options?.triggerOptions.motionTimeControl?.maxDuration

更新傳輸設定

本節說明如何變更傳輸設定。這會建立包含新值的新 TransportOptionsStruct,然後使用 modifyPushTransport 指令將這些更新的設定傳回裝置,並套用至上一個步驟中找到的錄製連線。

如要修改這些設定,請使用 modifyPushTransport 指令搭配 TransportOptionsStruct

// Example: Updating to Max Quality and 30s duration
let currentOptions = recordingConnection!.transportOptions!
let newOptions = Google.PushAvStreamTransportTrait.TransportOptionsStruct(
    streamUsage: .recording,
    videoStreamID: 2, // Max Quality
    tlsEndpointID: currentOptions.tlsEndpointID,
    url: currentOptions.url,
    triggerOptions: Google.PushAvStreamTransportTrait.TransportTriggerOptionsStruct(
        triggerType: .motion,
        motionSensitivity: 5, // Medium
        motionTimeControl: Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct(
            initialDuration: currentOptions.triggerOptions.motionTimeControl?.initialDuration ?? 10,
            augmentationDuration: currentOptions.triggerOptions.motionTimeControl?.augmentationDuration ?? 5,
            maxDuration: 30,
            blindDuration: currentOptions.triggerOptions.motionTimeControl?.blindDuration ?? 0
        )
    ),
    ingestMethod: currentOptions.ingestMethod,
    containerOptions: currentOptions.containerOptions
)

try await pushAvStreamTransportTrait.modifyPushTransport(
    connectionID: recordingConnection!.connectionID,
    transportOptions: newOptions
)

判斷頻寬品質

TransportOptionsStructvideoStreamId 屬性會對應至特定影片串流設定。

如要取得支援的影片串流,請參閱 allocatedVideoStreams 屬性,這是 VideoStreamStructs 的清單。裝置的 CameraAvStreamManagement 特徵。

調整裝置喚醒靈敏度

TransportTriggerOptionsStructmotionSensitivity 屬性對應下列值:

標籤 值 (UInt8)
1
5
10

調整事件錄影時間上限

TransportMotionTriggerTimeControlStructmaxDuration 屬性會對應至下列 UInt32 時間長度 (以秒為單位):

  • 10153060120180