iOS 裝置適用的門鈴裝置指南

門鈴裝置類型是使用三種特徵實作:PushAvStreamTransportTrait,使用推送通訊協定處理音訊和影片串流傳輸;WebRtcLiveViewTrait,提供控制直播和對講功能的能力;以及 CameraSnapshotTrait,提供快取預覽快照和即時快照擷取。

使用任何功能或嘗試更新屬性前,請務必確認裝置是否支援該屬性和指令。詳情請參閱「在iOS上控制裝置」。

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

門鈴

GoogleDoorbellDeviceType

home.matter.6006.types.0113

一種裝置,由門外的按鈕啟動,會發出聲音和/或視覺訊號,用於引起門內人員的注意。門鈴可能提供無障礙直播、雙向對講或偵測事件。

必要特徵
     google PushAvStreamTransportTrait
     google WebRtcLiveViewTrait

門鈴

取得裝置的基本資訊

   在 iOS 範例應用程式中導入   

BasicInformation 特性包含裝置的供應商名稱、供應商 ID、產品 ID、產品名稱 (包含型號資訊) 和軟體版本等資訊:

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!

取得序號

   在 iOS 範例應用程式中導入   

如要取得裝置序號,請使用 ExtendedBasicInformation 特性的 GetSerialNumber 指令。以下範例會將序號儲存在名為 serialNumber 的變數中:

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

應答短訊

「應答短訊」功能可讓使用者傳送預先定義的訊息給門鈴裝置。

這項功能僅適用於門鈴裝置。合作夥伴應用程式可取得預先定義的訊息清單,並向使用者顯示這些訊息供其選擇。使用者無法編輯預先定義的訊息。

應答短訊是透過 PresetMessage 特性實作。

播放預設訊息

如要播放預設訊息,請呼叫 playPresetMessage 方法,並傳遞 availablePhraseTypes 屬性中的其中一個字串值。


import GoogleHomeSDK
import GoogleHomeTypes

func playDoorbellPresetMessage(device: HomeDevice, phraseTypeString: String) async {
    // 1. Retrieve the GoogleDoorbellDeviceType helper on the device
    guard let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) else {
        print("This device is not a Google Doorbell or is currently uninitialized.")
        return
    }

    // 2. Extract the Google.PresetMessageTrait
    guard let presetMessageTrait = doorbellDeviceType.traits[Google.PresetMessageTrait.self] else {
        print("PresetMessageTrait is not supported on this device.")
        return
    }

    // 3. (Optional) Check available phrase types supported by the device
    if let availablePhrases = presetMessageTrait.attributes.availablePhraseTypes {
        let phraseTypeNames = availablePhrases.map { $0.phraseType }
        print("Supported quick response phrases: \(phraseTypeNames)")
    }

    // 4. Send the playPresetMessage command asynchronously
    do {
        try await presetMessageTrait.playPresetMessage(phraseType: phraseTypeString)
        print("Preset message successfully requested.")
    } catch {
        print("SDK error occurred playing preset message: \(error)")
    }
}

設定使用的語言

設定使用的語言

使用 LocalizationConfiguration 特性的 setActiveLocale 方法,將裝置的有效口語語言設為特定語言代碼 (例如「en_US」)。

// Setting the active language
// Assuming localizationConfigurationTrait: Matter.LocalizationConfigurationTrait
let selectedLocale = "en_US"
try await localizationConfigurationTrait.update {
    $0.setActiveLocale(selectedLocale)
}

取得裝置最近一次與雲端通訊的時間

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

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

攝影機安裝類型設定

Mount 特性包含攝影機固定座設定和狀態資訊。您可以讀取掛接狀態、偵測類型和掛接類型名稱等屬性。此外,您可以使用 Mount 特徵覆寫預設的掛接類型設定。

// 1. Get the Mount trait
guard let mountTrait = deviceType.traits[Google.MountTrait.self] else {
  print("Mount trait not supported or configured on this device.")
  return
}

// 2. Read the current mount state, detection type, and type name
let mountState         = mountTrait.attributes.mountState         // Type: Google.MountTrait.MountStateEnum?
let mountDetectionType = mountTrait.attributes.mountDetectionType // Type: Google.MountTrait.MountDetectionTypeEnum?
let mountTypeName      = mountTrait.attributes.mountTypeName      // Type: String?

// 3. Update the mount type override
try await mountTrait.update { mutableTrait in
  mutableTrait.setMountTypeOverride(.official)
}

檢查裝置的連線能力

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

let doorbellConnectivity = doorbellDeviceType.metadata.sourceConnectivity.connectivityState

如果裝置類型不一,且沒有網際網路連線,可能會看到 partiallyOnline 狀態。由於本機路由,Matter 標準特徵可能仍會上線,但雲端式特徵會離線。

取得裝置的 IP 位址

如要找出裝置的 IP 位址,請使用 GeneralDiagnosticsTrait 的 networkInterfaces 屬性。位址會以 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
}

開始直播

   在 iOS 範例應用程式中導入   

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

延長直播

   在 iOS 範例應用程式中導入   

直播影片有預設時間長度,超過就會失效。如要延長進行中直播的時間長度,請使用 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
  }
}

啟動及停止對講

   在 iOS 範例應用程式中導入   

如要啟動對講功能,請呼叫 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)")
  }
}

管理直播

   在 iOS 範例應用程式中導入   

調整直播畫質,可根據用戶端的觀看情境,最佳化頻寬用量 (例如在顯示較小的預覽圖塊、格狀檢視或子母畫面模式時,切換至較低解析度)。

使用 WebRtcLiveView 特性動態變更畫質,可專門管理特定用戶端上進行中直播工作階段的解析度。這與直接在裝置上設定裝置層級的頻寬用量不同,後者會影響所有同時觀看者,以及儲存到雲端的歷史錄影畫質。

以下範例說明如何擷取及更新裝置的直播畫質:

  • 擷取支援的畫質選項:取得裝置支援的串流解析度。程式碼會查詢 WebRtcLiveView 特性,並使用 supportedQualityHints 屬性,將支援的串流畫質顯示為 QualityHint 值清單 (例如 .sd、.hd、.fhd、.qhd 或 .uhd)。

  • 變更直播畫質:套用所選 QualityHint,變更進行中直播的串流解析度 (例如從標準畫質切換為高畫質)。updateQualityHint 函式會使用 WebRtcLiveView 特性的 changeLiveViewQuality 方法,將所選 QualityHint 設定套用至使用中的媒體工作階段。

public var supportedQualityHints: [Google.WebRtcLiveViewTrait.QualityHint] {
  return liveViewTrait?.attributes.supportedQualityHints ?? []
}

public func updateQualityHint(
  liveViewTrait: Google.WebRtcLiveViewTrait,
  hint: Google.WebRtcLiveViewTrait.QualityHint,
  mediaSessionId: String
) async {
  do {
    _ = try await liveViewTrait.changeLiveViewQuality(
      mediaSessionId: mediaSessionId,
      qualityHint: hint
    )
  } catch {
    // 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
}

擷取攝影機快照

   在 iOS 範例應用程式中導入   

使用 CameraSnapshot 特性,從攝影機擷取靜態圖片快照。這類快照適用於多種情境:

  • WebRTC 直播載入時,在 UI 中做為預留位置圖塊。
  • 以靜態預覽圖片顯示,使用者互動後會升級為直播。
  • 做為繪製及設定自訂活動區的背景畫布。

CameraSnapshot 特性提供兩種擷取快照的方式,取決於您需要快取快照以快速算繪,還是需要隨選即時快照。

取得快照預覽

預覽快照是快取圖片,SDK 無需喚醒相機即可擷取。這是擷取靜態圖片最快的方法,非常適合用於攝影機總覽頁面或資訊主頁格線。

如要取得預覽快照,請讀取 preview_image_url 特性屬性:

guard let cameraSnapshotTrait = deviceType.traits[
  Google.CameraSnapshotTrait.self
] else {
  print("CameraSnapshot trait not supported on this device.")
  return
}

if let previewImageUrlString = cameraSnapshotTrait
  .attributes.preview_image_url,
   let url = URL(string: previewImageUrlString) {
  // Load the preview image from the URL
}

視攝影機設定和活動而定,預覽網址會指向根據近期影片片段 (最新影片片段的第一個 I 影格) 產生的快取圖片,或是攝影機定期上傳的快照。

為表示圖片的新鮮度,Google Home 雲端會在提供的 JPEG/PNG 圖片中嵌入 X-Home-Image-Captured-At 標頭,格式為世界標準時間。您可以在用戶端剖析這個標頭,在應用程式中顯示快照的時間。

取得隨選即時快照

如果使用者歷程需要攝影機目前的即時監控畫面 (例如設定活動區),可以要求即時快照。觸發即時快照會指示攝影機喚醒、擷取新影格,並上傳到雲端。

如要要求即時快照,請使用 getLiveSnapshot() 指令:

do {
  let response = try await cameraSnapshotTrait.getLiveSnapshot()
  let snapshotUrlString = response.snapshot_url

  if let url = URL(string: snapshotUrlString) {
    // Load the live snapshot image from the URL
  }
} catch {
  print("Failed to get live snapshot: \(error)")
}

驗證快照要求

   在 iOS 範例應用程式中導入   

所有快照網址都會指向安全媒體,且需要 Home API v2 範圍的 OAuth 2.0 權杖。如要下載及算繪圖片,必須將 OAuth 權杖做為不記名權杖,插入 HTTP 要求的 Authorization 標頭。

以下範例說明如何設定安全的網路要求,以便下載快照:

import UIKit

func loadSnapshotImage(from url: URL, home: Home) async -> UIImage? {
  do {
    // 1. Retrieve the OAuth access token from the Home APIs SDK
    let (accessToken, _) = try await home.permissions.authorization()

    // 2. Configure the HTTP GET request with the Bearer token
    var request = URLRequest(url: url)
    request.setValue(
      "Bearer \(accessToken)",
      forHTTPHeaderField: "Authorization"
    )

    // 3. Fetch the image data
    let (data, _) = try await URLSession.shared.data(for: request)
    return UIImage(data: data)
  } catch {
    print("Error loading snapshot image: \(error)")
    return nil
  }
}

電池設定

你可以透過 Home API 控制各種電池設定。

設定電池用量偏好設定

設定能源平衡,即可在裝置的電池續航力和效能之間取得平衡。您可以建立不同的電池設定檔,例如「延長」、「平衡」和「效能」,並在這些設定檔之間切換。

如要實作這項功能,請更新 EnergyPreference 特性的 currentEnergyBalance 屬性。這個屬性接受整數索引,對應到裝置 energyBalances 清單中定義的特定設定檔 (例如 0 對應 EXTENDED、1 對應 BALANCED、2 對應 PERFORMANCE)。

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

以下範例說明 currentEnergyBalance 屬性會使用的結構,接著是使用該屬性的實際程式碼片段。

// Example energyBalances list
{
  "energy_balances": [
    {
      "step": 0,
      "label": "EXTENDED"
    },
    {
      "step": 50,
      "label": "BALANCED"
    },
    {
      "step": 100,
      "label": "PERFORMANCE"
    }
  ]
}
private func setBatteryUsage(to option: UInt8) async throws {
  _ = try await energyPreferenceTrait.update {
    $0.setCurrentEnergyBalance(option)
  }
}

開啟自動省電模式

   在 iOS 範例應用程式中導入   

如要設定這項功能,請更新 EnergyPreference 特性的 currentLowPowerModeSensitivity 屬性。這項屬性會使用索引選取敏感度等級,其中 0 通常代表 Disabled,1 則代表 Enabled 或 Automatic。

private func setAutoBatterySaver(to value: Bool) async throws {
  _ = try await energyPreferenceTrait.update {
    $0.setCurrentLowPowerModeSensitivity(value ? 1 : 0)
  }
}

取得電池充電狀態

   在 iOS 範例應用程式中導入   

如要取得裝置目前的充電狀態 (充電中、已充飽電或未充電),請使用 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
}

檢查是否需要更換電池

batReplaceability 屬性會指出電池是否不可更換、可由使用者更換,或可由原廠更換。

如果電池可更換,PowerSource 特性的 batReplacementNeeded 屬性會指出是否需要更換電池。

// Get the battery replacement status
var batteryStatus = powerSourceTrait.attributes.batReplacementNeeded

if batteryStatus {
  print("Replace the battery.")
}

如果電池可由使用者更換,batReplacementDescription 會描述電池,包括外型規格、化學成分和偏好製造商等資訊。

音訊設定

你可以透過 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
  }
}

活動區設定

   在 iOS 範例應用程式中導入   

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

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

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

查看活動區

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

let zoneManagementTrait: Google.ZoneManagementTrait

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

新增活動區

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

以下範例說明如何建立名為「Front Porch」的區域,該區域有四個頂點,顏色為鮭魚色 (#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 偵測一氧化碳 (CO) 警報,通常會發出 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
)

錄製模式

   在 iOS 範例應用程式中導入   

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

RecordingModeEnum 定義可用的錄製策略:

模式 列舉值 說明
已停用 Disabled 完全停用錄製功能。主要由舊版裝置使用。
CVR (連續錄影) Cvr 全天候錄影。須訂閱 (例如 Google Home Premium。
EBR (事件錄影) 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,
      )
    )
  }
}

變更錄製模式

更新前,請確認 availableRecordingModes 屬性中包含從 supportedRecordingModes 屬性選擇的索引。

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

let recordingModeTrait: Google.RecordingModeTrait
let recordingModeID: UInt8

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

其他設定

你可以透過 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 的值取決於應用程式的 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,則必須先產生這個結構,才能更新任何屬性。

使用這個輔助函式產生 struct,以便用於下列設定變更:

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」)。

如要啟用裝置的數據分析功能,請將 ExtendedGeneralDiagnosticsTrait 的 analyticsEnabled) 屬性設為 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
)

判斷頻寬品質

TransportOptionsStruct 的 videoStreamId 屬性對應至特定影片串流設定。

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

調整裝置喚醒靈敏度

TransportTriggerOptionsStruct 的 motionSensitivity 屬性對應下列值:

標籤 值 (UInt8)
低 1
中 5
高 10

調整事件錄影時間上限

TransportMotionTriggerTimeControlStruct 的 maxDuration 屬性對應下列 UInt32 持續時間 (以秒為單位):

  • 10、15、30、60、120、180

電鈴設定

你可以透過 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
  }
}

使用外接電鈴

   在 iOS 範例應用程式中導入   

你可以將門鈴設為使用外部電鈴,例如安裝在住家內部的機械式電鈴。請務必在安裝門鈴時完成這項設定,以免損壞外接電鈴。

如要指出安裝的外接電鈴類型,請使用 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
  }
}

啟用鈴聲主題

   在 iOS 範例應用程式中導入   

部分門鈴的鈴聲可能僅限時提供。例如節慶專屬鈴聲。 這些稱為「提示音主題」。

如要查看使用者可用的鈴聲主題,請建立時間盒篩選器,並用來篩選 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 &lt;= currentDateTime
      &amp;&amp; chimeTheme.endTimeSeconds ?? UInt64.max &gt;= 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)
  }
}

訪客通報設定

您可以使用 Home API 的 VisitorAnnouncement 特性,查詢及管理門鈴的訪客通報設定。這項特性能控制是否要在有人按門鈴時,透過 Google 智慧音箱或螢幕通報訪客到來。

以下範例說明如何檢查是否已啟用訪客通報功能,以及如何更新這項設定:

let visitorAnnouncementsEnabled: Bool = visitorAnnouncementTrait.attributes.visitorAnnouncementsEnabled

let value: Bool
_ = try await self.visitorAnnouncementTrait?.update {
  $0.setVisitorAnnouncementsEnabled(value)
}

停用裝置

如要從結構體中移除門鈴,請呼叫 device.decommission()。停用時,系統會向使用者顯示 Google 管理的確認畫面,警告所有記錄的全天候錄影記錄、事件記錄、剪輯片段和熟面孔資料庫資料,都會從住家中永久刪除。

如需詳細操作說明和程式碼範例,請參閱「移除裝置」。