iOS 向けドアベル デバイスガイド

ドアホン デバイスタイプは、3 つのトレイトを使用して実装されます。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 向けサンプルアプリに実装済み   

ライブ配信を開始するには、Session Description Protocol(SDP)文字列を WebRtcLiveViewTrait トレイトの startLiveView(offerSdp:) メソッドに送信します。このメソッドは次の 3 つの値を返します。

  • セッションの 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
  }
}

TalkBack を開始、停止する

   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 トレイトをクエリして、サポートされているストリーム品質を QualityHint 値のリスト(.sd、.hd、.fhd、.qhd、.uhd など)として公開します。supportedQualityHints プロパティを使用します。

  • ライブ配信の画質を変更する: 選択した 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
    }
  }
}

カメラの録画機能を有効または無効にすることは、カメラの動画をオンまたはオフにすることと同じです。カメラの動画がオンの場合、録画が行われます(アクティビティや関連するクリップのため)。

録画機能が無効になっている場合(カメラの動画がオフの場合):

  • カメラは、デバイスタイプの connectivityState に従ってオンラインとして表示されます。
  • ライブ配信にアクセスできず、カメラがクラウド イベントを検出することもありません。

録画機能が有効になっているかどうかを確認する

カメラの録画機能が有効になっているかどうかを判断するには、アクティブな接続があるかどうかを確認します。次の例では、これを行う 2 つの関数を定義しています。

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 トレイトには、高速レンダリング用のキャッシュに保存されたスナップショットが必要か、オンデマンドのライブ スナップショットが必要かに応じて、スナップショットを取得する 2 つの方法が用意されています。

キャッシュに保存されたプレビュー スナップショットを取得する

プレビュー スナップショットは、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
}

カメラの設定とアクティビティに応じて、プレビュー URL は、最近の動画映像(最新の動画フラグメントの最初の I フレーム)から生成されたキャッシュに保存された画像、またはカメラによって定期的にアップロードされたスナップショットを指します。

画像の鮮度を示すため、Google Home クラウドは、提供される JPEG/PNG 画像に X-Home-Image-Captured-At ヘッダーを埋め込みます。このヘッダーは UTC 形式です。このヘッダーをクライアント側で解析して、アプリにスナップショットの経過時間を表示できます。

オンデマンドのライブ スナップショットを取得する

アクティビティ エリアの設定など、カメラの現在のライブビューが必要なユーザー ジャーニーでは、ライブ スナップショットをリクエストできます。ライブ スナップショットをトリガーすると、カメラが起動して新しいフレームをキャプチャし、クラウドにアップロードします。

ライブ スナップショットをリクエストするには、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 向けサンプルアプリに実装済み   

すべてのスナップショット URL は安全なメディアを指しており、Home APIs 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 リストで定義されている特定のプロファイルに対応する整数インデックスを受け入れます(たとえば、EXTENDED の場合は 0、BALANCED の場合は 1、PERFORMANCE の場合は 2)。

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

自動バッテリー セーバーをオンにする

   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 を受け取ります。

次の例は、4 つの頂点を持つ「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
}

アクティビティ エリアを削除する

ゾーンを削除するには、特定の zoneId を指定して removeZone コマンドを使用します。

let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16

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

サウンドに関するアクティビティのトリガー

AvStreamAnalysis トレイトは、カメラやドアホン デバイスのアクティビティ検出トリガーを管理するためのインターフェースを提供します。ビジョンベースのトリガー(人や車両など)はエリア固有にできますが、音関連のトリガーは通常、デバイスレベルの設定です。

EventTriggerTypeEnum のサウンド検知では、次のトリガータイプを使用できます。

モード 列挙値 説明
サウンド Sound 一般的なサウンド検知。
話し声 PersonTalking 音声を検出します。
犬の吠える声 DogBark 犬の鳴き声を検出します。
ガラスの割れる音 GlassBreak ガラスの割れる音を検知します。
煙警報 SmokeAlarm 煙警報を検出します。多くの場合、T3 音声パターン(3 回の短いビープ音の後に一時停止)で認識されます。
一酸化炭素警報 CoAlarm 一酸化炭素(CO)警報を検知します。通常、T4 音声パターン(4 回の短いビープ音の後に一時停止)で認識されます。

サウンド検知のステータスを確認する

サウンド検知の現在の状態をユーザーに表示するには、デバイスがサポートしている機能と、デバイス ハードウェアで有効になっている機能を確認する必要があります。確認する 2 つの属性は次のとおりです。

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 動画は 24 時間 365 日録画されます。サブスクリプション(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,
      )
    )
  }
}

録画モードを変更する

更新する前に、supportedRecordingModes 属性から選択したインデックスが availableRecordingModes 属性に存在することを確認してください。

選択したモードを更新するには、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
  }
}

カメラのビューポートを変更する

カメラのビューポートは、Google Nest カメラの動画でズーム機能や補正機能を使用するのサポート記事に記載されているズームと切り抜き機能と同じです。

ビューポートは、4 つの値を含む ViewportStruct で定義されます。これらの値は、ビューポートの座標として使用されます。座標は次のように定義されます。

(x1,y1) -- (x2,y1)
   |          |
(x1,y2) -- (x2,y2)

ViewportStruct の値は、アプリの UI とカメラの実装によって異なります。ごく基本的なレベルでは、カメラ動画のビューポートを設定するには、組み込みの setViewport 関数を使用して、CameraAvStreamManagementTrait トレイトの viewport 属性を ViewportStruct で更新します。

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 APIs の 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 コマンドを使用して、更新された設定をデバイスに送信し、前のステップで見つかった録音接続に適用します。

これらの設定を変更するには、TransportOptionsStruct を指定して modifyPushTransport コマンドを使用します。

// 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 が管理する確認画面が表示され、録画された連続動画履歴、アクティビティの履歴、クリップ、認識済みの人物ライブラリのデータがすべて、ストラクチャ全体で完全に削除されることが警告されます。

詳細な手順とコード例については、デバイスを削除するをご覧ください。