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

ドアホン デバイスタイプは、2 つのトレイトを使用して実装されます。PushAvStreamTransport は、プッシュベースのプロトコルを使用して音声と動画のストリーム転送を処理します。WebRtcLiveView は、ライブ ストリームとトークバックを制御する機能を提供します。

機能を使用したり、属性を更新しようとしたりする前に、デバイスの属性とコマンドのサポートを必ず確認してください。詳しくは、Androidでデバイスを制御するをご覧ください。

Google Home の API のデバイスタイプ トレイト Kotlin サンプルアプリ ユースケース

ドアホン

GoogleDoorbellDevice

home.matter.6006.types.0113

ドアの外側のボタンを押すと、音や光の信号を発するデバイス。ドアの向こう側にいる人の注意を引くために使用されます。ドアホンには、アクセシビリティ対応のライブ配信、双方向のトークバック、検出イベントなどの機能が搭載されている場合があります。

必須のトレイト
     google PushAvStreamTransport
     google WebRtcLiveView

ドアホン

デバイスに関する基本情報を取得する

   Android 用サンプルアプリで実装   

BasicInformation トレイトには、ベンダー名、ベンダー ID、プロダクト ID、プロダクト名(モデル情報を含む)、デバイスのソフトウェア バージョンなどの情報が含まれます。

// Get device basic information. All general information traits are on the RootNodeDevice type.
    device.type(RootNodeDevice).first().standardTraits.basicInformation?.let { basicInformation ->
        println("vendorName ${basicInformation.vendorName}")
        println("vendorId ${basicInformation.vendorId}")
        println("productId ${basicInformation.productId}")
        println("productName ${basicInformation.productName}")
        println("softwareVersion ${basicInformation.softwareVersion}")
    }

シリアル番号を取得する

デバイスのシリアル番号を取得するには、ExtendedBasicInformation トレイトの GetSerialNumber コマンドを使用します。この例では、シリアル番号を serialNumber という名前の変数に保存しています。

val basicInfo: ExtendedBasicInformation = device.getTrait(ExtendedBasicInformation)
val serialNumber = basicInfo.getSerialNumber().serialNumber

クイック応答

クイック応答機能を使用すると、ユーザーは事前に定義されたメッセージをドアホン デバイスに送信できます。

この機能は、ドアベル デバイスでのみご利用いただけます。事前定義されたメッセージのリストはパートナー アプリで利用でき、ユーザーが選択できるように表示できます。事前定義されたメッセージはユーザーが編集できません。

クイック レスポンスは PresetMessage トレイトを介して実装されます。

プリセットのメッセージを再生する

プリセット メッセージを再生するには、availablePhraseTypes プロパティにある文字列値のいずれかを渡して、playPresetMessage メソッドを呼び出します。

import com.google.home.HomeDevice
import com.google.home.HomeException
import com.google.home.google.GoogleDoorbellDevice
import com.google.home.google.PresetMessage
import kotlinx.coroutines.flow.first

suspend fun playDoorbellPresetMessage(device: HomeDevice, phraseTypeString: String) {
    try {
        // 1. Retrieve the first snapshot of the doorbell device type
        val doorbellDevice = device.type(GoogleDoorbellDevice).first()

        // 2. Extract the PresetMessage trait
        val presetMessageTrait = doorbellDevice.trait(PresetMessage)
        if (presetMessageTrait == null) {
            println("PresetMessage trait is not supported on this doorbell device.")
            return
        }

        // 3. (Optional) Check available phrase types supported by the device
        val availablePhrases = presetMessageTrait.availablePhraseTypes
        if (availablePhrases != null) {
            val phraseTypesList = availablePhrases.map { it.phraseType }
            println("Supported quick response phrases: $phraseTypesList")
        }

        // 4. Send the playPresetMessage command to the doorbell
        presetMessageTrait.playPresetMessage(phraseType = phraseTypeString)
        println("Preset message command sent successfully.")

    } catch (e: HomeException) {
        println("Home API error occurred: ${e.message}")
    } catch (e: Exception) {
        println("Unexpected failure: ${e.message}")
    }
}

音声言語を設定する

LocalizationConfiguration トレイトの setActiveLocale メソッドを使用して、デバイスのアクティブな音声言語を特定のロケール(「en_US」など)に設定します。

import java.util.Locale

// Convert underscore format (en_US) to Java Locale
fun String.toLocale(): Locale = Locale.forLanguageTag(this.replace('_', '-'))

// Setting the active language
val trait: LocalizationConfiguration = device.getTrait(LocalizationConfiguration)
val selectedLocale = "en_US" // Target locale string
trait.update {
    setActiveLocale(selectedLocale)
}

デバイスがクラウドに最後に接続した日時を取得する

デバイスがクラウドと最後に通信した時刻を確認するには、ExtendedGeneralDiagnostics トレイトの lastContactTimestamp 属性を使用します。

fun getLastContactTimeStamp(trait: ExtendedGeneralDiagnostics): java.time.Instant {
  val timestamp = trait.lastContactTimestamp
  return Instant.ofEpochSecond(timestamp.toLong())
}

カメラマウントのタイプの設定

Mount トレイトには、カメラのマウント設定とステータス情報が含まれています。マウント状態、検出タイプ、マウント タイプ名などの属性を読み取ることができます。また、Mount トレイトを使用して、デフォルトのマウントタイプの構成をオーバーライドすることもできます。

// Get the Mount trait
val mountTrait: Mount = device.getTrait(Mount)

// Read the current mount state and detection type
val mountState = mountTrait.mountState
val mountDetectionType = mountTrait.mountDetectionType

// Read the current mount type name
val mountTypeName = mountTrait.mountTypeName

// Update the mount type override
mountTrait.update {
  setMountTypeOverride(MountTrait.MountTypeOverrideEnum.Official)
}

デバイスの接続を確認する

デバイスの接続は、実際にはデバイスタイプ レベルでチェックされます。一部のデバイスは複数のデバイスタイプをサポートしているためです。返される状態は、そのデバイスのすべてのトレイトの接続状態の組み合わせです。

   Android 用サンプルアプリで実装   
val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

インターネット接続がない場合、デバイスタイプが混在していると PARTIALLY_ONLINE の状態になることがあります。Matter 標準特性はローカル ルーティングによりオンラインのままになる可能性がありますが、クラウドベースの特性はオフラインになります。

デバイスの IP アドレスを取得する

デバイスの IP アドレスを取得するには、GeneralDiagnostics トレイトの networkInterfaces 属性を使用します。アドレスはバイト配列として返されます。この配列は、標準の IPv4 または IPv6 文字列にフォーマットできます。

val ipAddresses =
  trait.networkInterfaces?.flatMap { networkInterface ->
    (networkInterface.ipv4Addresses + networkInterface.ipv6Addresses).mapNotNull { bytes ->
      try {
        java.net.InetAddress.getByAddress(bytes).hostAddress
      } catch (e: java.net.UnknownHostException) {
        null
      }
    }
  } ?: emptyList()

ライブ配信を開始する

   Android 用サンプルアプリで実装   

ライブ配信を開始するには、セッション記述プロトコル(SDP)文字列を WebRtcLiveView トレイトの startLiveView() メソッドに送信します。このメソッドは、次の 3 つの値を含む WebRtcLiveViewTrait.StartLiveViewCommand.Response を返します。

  • セッションの SDP。
  • セッションの長さ(秒数)。
  • セッションの延長または終了に使用できるセッション ID。
suspend fun getWebRtcLiveViewTrait(cameraDevice: HomeDevice) {
 return cameraDevice.type(GoogleDoorbellDevice).trait(WebRtcLiveView).first {
    it?.metadata?.sourceConnectivity?.connectivityState == ConnectivityState.ONLINE
  }

}

// Start the live view
suspend fun startCameraStream(trait: WebRtcLiveView, offerSdp: String) {
  val response = trait.startLiveView(offerSdp)
  // Response contains three fields (see below)
  return response
}
  ...

// This is used to manage the WebRTC connection
val peerConnection: RTCPeerConnection = ...

   ...

val startResponse = startCameraStream(sdp)
val answerSdp = startResponse?.answerSdp
val sessionDuration = startResponse?.liveSessionDurationSeconds
val mediaSessionId = startResponse?.mediaSessionId

peerConnection.setRemoteDescription(SessionDescription.Type.ANSWER,
                                    answerSdp)

ライブ配信を延長する

   Android 用サンプルアプリで実装   

ライブ配信には、期限切れになるまでの期間が事前に設定されています。アクティブなストリームの期間を延長するには、WebRtcLiveView.extendLiveView() メソッドを使用して延長リクエストを発行します。

// Assuming camera stream has just been started
suspend fun scheduleExtension(trait: WebRtcLiveView, mediaSessionId: String, liveSessionDurationSeconds: UShort ) {
  delay(liveSessionDurationSeconds - BUFFER_SECONDS * 1000)
  val response = trait.extendLiveView(mediaSessionId)
  // returns how long the session will be live for
  return response.liveSessionDurationSeconds
}

TalkBack の開始と停止

   Android 用サンプルアプリで実装   

TalkBack を開始するには、WebRtcLiveView トレイトの startTalkback() メソッドを呼び出します。停止するには、stopTalkback() を使用します。

// Make sure camera stream is on
suspend fun setTalkback(isOn: Boolean, trait: WebRtcLiveView, mediaSessionId: String) {
  if(isOn) {
    trait.startTalkback(mediaSessionId)
  } else {
    trait.stopTalkback(mediaSessionId)
  }
}

録画機能を有効または無効にする

カメラの録画機能を有効にするには、PushAvStreamTransport トレイトの setTransportStatus() メソッドに TransportStatusEnum.Active を渡します。録画機能を無効にするには、TransportStatusEnum.Inactive を渡します。次の例では、これらの呼び出しを 1 つの呼び出しでラップし、Boolean を使用して録音機能を切り替えます。

// Start or stop recording for all connections.
suspend fun setCameraRecording(trait: PushAvStreamTransport, isOn: Boolean) {
  if(isOn) {
    trait.setTransportStatus(TransportStatusEnum.Active)
  } else {
    trait.setTransportStatus(TransportStatusEnum.Inactive)
  }
}

カメラの録画機能を有効または無効にすることは、カメラの動画のオンとオフを切り替えることと同じです。カメラの動画がオンになっている場合、イベントと関連するクリップの目的で録画が行われます。

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

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

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

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

// Get the on/off state
suspend fun onOffState(pushAvStreamTransport: PushAvStreamTransport) {
  return pushAvStreamTransport
    .currentConnections?.any { it.transportStatus == TransportStatusEnum.Active } ?: false
}

// Check if the camera's recording capability is enabled
fun PushAvStreamTransport.recordModeActive(): Boolean {
  return currentConnections?.any { it.transportStatus == TransportStatusEnum.Active } ?: false
}

別の方法として、述語を使用して findTransport() 関数を使用することもできます。

// Fetch the current connections
suspend fun queryRecordModeState(trait: PushAvStreamTransport) {
  return trait.findTransport().let {
      it.transportConfigurations.any { it.transportStatus == TransportStatusEnum.Active
    }
}

カメラのスナップショットを取得する

CameraSnapshot トレイトを使用して、カメラから静止画像のスナップショットを取得します。これらのスナップショットは、次のようなシナリオで役立ちます。

  • WebRTC ライブストリームの読み込み中に UI のプレースホルダ タイルとして。
  • ユーザー操作時にライブ配信にアップグレードされる静的なプレビュー画像として。
  • カスタムのアクティビティ ゾーンを描画して構成するためのバックグラウンド キャンバスとして。

CameraSnapshot トレイトは、高速レンダリング用のキャッシュ保存されたスナップショットが必要か、オンデマンドのライブ スナップショットが必要かに応じて、スナップショットを取得する 2 つの方法を提供します。

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

プレビュー スナップショットは、SDK がカメラを起動せずに取得できるキャッシュ保存された画像です。これは静的画像を取得する最も高速な方法であり、カメラの概要ページやダッシュボードのグリッドに最適です。

プレビュー スナップショットを取得するには、preview_image_url トレイト属性を読み取ります。

// Get a flow of the CameraSnapshot trait
val cameraSnapshotFlow: Flow<CameraSnapshot?> = cameraDevice
  .type(GoogleCameraDevice)
  .trait(CameraSnapshot)

// Get the current trait state
val cameraSnapshot = cameraSnapshotFlow.firstOrNull()
if (cameraSnapshot != null) {
  val previewImageUrl = cameraSnapshot.previewImageUrl
  // Load the preview image from the URL
} else {
  // CameraSnapshot trait not supported on this device
}

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

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

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

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

ライブ スナップショットをリクエストするには、getLiveSnapshot() コマンドを使用します。

try {
  val response = cameraSnapshot.getLiveSnapshot()
  val snapshotUrl = response.snapshotUrl
  // Load the live snapshot image from the URL
} catch (e: Exception) {
  Log.e("CameraSnapshot", "Failed to get live snapshot: ${e.message}")
}

スナップショット リクエストを認証する

すべてのスナップショット URL は安全なメディアを指しており、Home API v2 スコープの OAuth 2.0 トークンが必要です。画像をダウンロードしてレンダリングするには、OAuth トークンを HTTP リクエストの Authorization ヘッダーにベアラー トークンとして挿入する必要があります。

次の例は、スナップショットをダウンロードするための安全なネットワーク リクエストを構成する方法を示しています。

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

/**
 * Downloads a snapshot from a URL using an OAuth access token.
 */
suspend fun loadSnapshotImage(urlString: String, oauthToken: String): Bitmap? =
  withContext(Dispatchers.IO) {
    var connection: HttpURLConnection? = null
    try {
      val url = URL(urlString)
      connection = url.openConnection() as HttpURLConnection
      // 1. Configure the HTTP GET request with the Bearer token
      connection.setRequestProperty("Authorization", "Bearer $oauthToken")

      // 2. Fetch the image data
      if (connection.responseCode == HttpURLConnection.HTTP_OK) {
        connection.inputStream.use { inputStream ->
          BitmapFactory.decodeStream(inputStream)
        }
      } else {
        null
      }
    } catch (e: IOException) {
      e.printStackTrace()
      null
    } finally {
      connection?.disconnect()
    }
  }

ライブ配信を管理する

ライブ配信の画質を調整すると、クライアントの視聴コンテキストに基づいて帯域幅の使用量を最適化できます(たとえば、プレビュー タイル、グリッド ビュー、ピクチャー イン ピクチャー モードの表示が小さい場合は、解像度を下げます)。

WebRtcLiveView トレイトを使用して品質を動的に変更すると、特定のクライアントでアクティブなライブ ストリーミング セッションの解像度が管理されます。デバイス全体の帯域幅使用量設定をデバイスで直接構成する場合とは異なり、この設定は、同時に視聴しているすべてのユーザーや、クラウドに保存されている過去の動画録画の画質に影響することはありません。

次の例は、デバイスのライブ配信の品質を取得して更新する方法を示しています。

  • サポートされている画質オプションを取得する: デバイスでサポートされているストリーミング解像度を取得します。このコードは、デバイスタイプのフローで WebRtcLiveView トレイトの supportedQualityHints 属性をクエリし、サポートされている画質を QualityHint 値(QUALITY_HINT_SDQUALITY_HINT_HDQUALITY_HINT_FHDQUALITY_HINT_QHDQUALITY_HINT_UHD など)のリストを含む StateFlow として公開します。

  • ライブ配信の画質を変更する: 選択した QualityHint を適用して、アクティブなライブ配信のストリーミング解像度を変更します(標準画質から高画質への切り替えなど)。changeQuality 関数は、デバイスのライブ ストリーミング トレイトを解決し、アクティブな mediaSessionId と選択された QualityHint 構成で changeLiveViewQuality を呼び出します。

// Assuming you have a HomeDevice instance 'device'
val availableQualityHints: StateFlow<List> =
    device.type(GoogleDoorbellDevice)
        .trait(WebRtcLiveView)
        .map { trait -> 
            trait?.supportedQualityHints ?: emptyList() 
        }
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())

// Assuming you have a HomeDevice instance 'device'
suspend fun changeQuality(mediaSessionId: String, qualityHint: QualityHint) {
    // Get the trait from the device
    val trait = device.type(GoogleDoorbellDevice).trait(WebRtcLiveView).first() ?: return
    try {
        trait.changeLiveViewQuality(mediaSessionId, qualityHint)
    } catch (e: Exception) {
        // Handle error
    }
}

バッテリーの設定

さまざまなバッテリー設定は、Home API を介して制御できます。

バッテリー使用量の設定を行う

エネルギー バランスを設定すると、デバイスのバッテリー駆動時間とパフォーマンスのトレードオフを構成できます。「延長」、「バランス」、「パフォーマンス」などのさまざまなバッテリー プロファイルを作成して、切り替えることができます。

この機能は、EnergyPreference トレイトの currentEnergyBalance 属性を更新することで実装されます。この属性は、デバイスの energyBalances リストで定義された特定のプロファイルに対応する整数インデックスを受け入れます(たとえば、EXTENDED の場合は 0BALANCED の場合は 1PERFORMANCE の場合は 2)。

currentEnergyBalancenull 値は、デバイスがカスタム プロファイルを使用していることを示します。読み取り専用の状態です。

以下に、currentEnergyBalance 属性が使用する構造の例と、その属性を使用する実際のコード スニペットを示します。

// Example energyBalances list
energy_balances: [
  {
    step: 0,
    label: "EXTENDED"
  },
  {
    step: 50,
    label: "BALANCED"
  },
  {
    step: 100,
    label: "PERFORMANCE"
  }
]
// The index parameter must be within the UByte range (0-255).
suspend fun setEnergyBalance(trait: EnergyPreference, index: Int) {
  trait.update { setCurrentEnergyBalance(index.toUByte()) }
}

// Setting the battery usage to more recording ie performance
setEnergyBalance(energyPreference, 2)

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

この機能を構成するには、EnergyPreference トレイトの currentLowPowerModeSensitivity 属性を更新します。この属性は、インデックスを使用して感度レベルを選択します。通常、0Disabled を表し、1Enabled または Automatic を表します。

suspend fun setAutomaticBatterySaver(enable: Boolean, trait: EnergyPreference) {
  // 0 is Disabled, 1 is Enabled
  val value = if (enable) 1.toUByte() else 0.toUByte()
  trait.update { setCurrentLowPowerModeSensitivity(value) }
}

バッテリーの充電状態を取得する

デバイスの現在の充電状態(充電中、充電完了、充電していない)を取得するには、PowerSource トレイトの batChargeState 属性を使用します。

// Get the battery charging state
val batteryChargeState = powerSource.batChargeState

when (batteryChargeState) {
    PowerSourceTrait.BatChargeStateEnum.IsCharging -> "Charging"
    PowerSourceTrait.BatChargeStateEnum.IsAtFullCharge -> "Full"
    PowerSourceTrait.BatChargeStateEnum.IsNotCharging -> "Not Charging"
    else -> "Unknown"
}

バッテリー残量を取得する

現在のバッテリー残量を取得するには、PowerSource トレイトの batChargeLevel 属性を使用します。レベルは OKWarning(低)、Critical のいずれかです。

// Get the battery charge level
val batteryLevel = powerSourceTrait.batChargeLevel

when (batteryLevel) {
    PowerSourceTrait.BatChargeLevelEnum.OK -> "OK"
    PowerSourceTrait.BatChargeLevelEnum.Warning -> "Warning"
    PowerSourceTrait.BatChargeLevelEnum.Critical -> "Critical"
    else -> "Unknown"
}

電源を取得する

デバイスが使用している電源を判断するには、PowerSource トレイトの BatPresent 属性と wiredPresent 属性を使用します。

  val trait: PowerSource
  val isWired = trait.wiredPresent
  val hasBattery = trait.batPresent

バッテリーの交換が必要かどうかを確認する

batReplaceability 属性は、バッテリーが交換不可、ユーザー交換可能、工場交換可能のいずれであるかを示します。

PowerSource トレイトの batReplacementNeeded 属性は、バッテリーの交換が必要かどうかを示します。

// Get the battery replacement status
val batteryStatus = powerSourceTrait.batReplacementNeeded

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

バッテリーがユーザー交換可能な場合、batReplacementDescription は、フォーム ファクタ、化学組成、推奨メーカーなどの情報を含むバッテリーを説明します。

音声設定

さまざまな音声設定は、Home API を介して制御できます。

マイクのオンとオフを切り替える

デバイスのマイクのオンとオフを切り替えるには、組み込みの setMicrophoneMuted Kotlin 関数を使用して、CameraAvStreamManagement トレイトの microphoneMuted 属性を更新します。

// Turn the device's microphone on or off
suspend fun turnOffMicrophone(disableMicrophone: Boolean, trait: CameraAvStreamManagement) {
  trait.update { setMicrophoneMuted(disableMicrophone) }
}

録音のオンとオフを切り替える

デバイスの録音のオンとオフを切り替えるには、組み込みの setRecordingMicrophoneMuted Kotlin 関数を使用して、CameraAvStreamManagement トレイトの recordingMicrophoneMuted 属性を更新します。

// Turn audio recording on or off for the device
suspend fun turnOffAudioRecording(disableAudioRecording: Boolean, trait: CameraAvStreamManagement) {
  trait.update { setRecordingMicrophoneMuted(disableAudioRecording) }
}

スピーカーの音量を調整する

デバイスのスピーカー音量を調整するには、組み込みの setSpeakerVolumeLevel Kotlin 関数を使用して、CameraAvStreamManagement トレイトの speakerVolumeLevel 属性を更新します。

// Adjust the camera speaker volume
suspend fun adjustSpeakerVolume(volume: Int, trait: CameraAvStreamManagement) {
  trait.update { setSpeakerVolumeLevel(volume.toUbyte()) }
}

アクティビティ エリアの設定

   Android 用サンプルアプリで実装   

ZoneManagement トレイトは、カメラ デバイスとドアホン デバイスのカスタムの対象領域(アクティビティ エリア)を管理するためのインターフェースを提供します。これらのゾーンは、デバイスの視野内の特定のエリアでイベント検出(人物や車両の動きなど)をフィルタするために使用されます。

アクティビティ エリアは、パートナー アプリケーション内でユーザーが設定します。これにより、カメラの視野内の特定のエリアにエリアを描画できます。これらのユーザー定義ゾーンは、このトレイトで使用される構造に変換されます。アクティビティ エリアの仕組みについて詳しくは、アクティビティ エリアを設定して使用するをご覧ください。

アクティビティ ゾーンは通常、2D の直交座標を使用して定義されます。このトレイトは、頂点の TwoDCartesianVertexStruct と、ゾーン定義(名前、頂点、色、用途)の TwoDCartesianZoneStruct を提供します。

アクティビティ エリアを確認する

アクティビティ エリアを表示するには、ZoneManagement トレイトの zones 属性を確認します。

// 1. Obtain the trait flow from the device
private val zoneManagementFlow: Flow =
  device.type(CAMERA_TYPE).flatMapLatest { it.trait(ZoneManagement) }

// 2. Map the flow to the list of zone structures
val activityZones: Flow<List<ZoneManagementTrait.ZoneInformationStruct>> =
  zoneManagementFlow.map { trait ->
    trait.zones ?: emptyList()
  }

アクティビティ エリアを追加する

新しいゾーンを作成するには、createTwoDCartesianZone コマンドを使用します。このコマンドは、ゾーンの名前、頂点、色、使用状況を定義する TwoDCartesianZoneStruct を使用します。

次の例は、4 つの頂点を持つ「Front Porch」という名前のゾーンを作成し、サーモン色(#F439A0)で塗りつぶして、モーション検出に使用する方法を示しています。

import com.google.home.google.ZoneManagement
import com.google.home.google.ZoneManagementTrait
import com.google.home.matter.serialization.OptionalValue

/**
 * Creates a custom activity zone named "Front Porch" with a salmon color
 * configured for motion detection.
 */
suspend fun createFrontPorchZone(zoneManagement: ZoneManagement) {
  // 1. Define the vertices for the zone (2D Cartesian coordinates)
  // Values are typically scaled to a maximum defined by the device's twoDCartesianMax attribute.
  val vertices =
    listOf(
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 260u, y = 422u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1049u, y = 0u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048u, y = 0u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048u, y = 950u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1630u, y = 1349u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 880u, y = 2048u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 0u, y = 2048u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 638u, y = 1090u)
    )

  // 2. Define the zone structure
  val newZone =
    ZoneManagementTrait.TwoDCartesianZoneStruct(
      name = "Front Porch",
      vertices = vertices,
      // Usage defines what the zone filters (for example, Motion, Person, Vehicle)
      use = listOf(ZoneManagementTrait.ZoneUseEnum.Motion),
      // Color is typically a hex string (for example, Salmon/Pink)
      color = OptionalValue.present("#F439A0")
    )

  try {
    // 3. Execute the command to add the zone to the device
    zoneManagement.createTwoDCartesianZone(newZone)
    println("Successfully created activity zone.")
  } catch (e: Exception) {
    // Handle potential HomeException or Timeout
    println("Failed to create activity zone: ${e.message}")
  }
}

アクティビティ エリアを更新する

既存のゾーンを更新するには、updateTwoDCartesianZone コマンドを使用します。このコマンドには、zoneId と更新された TwoDCartesianZoneStruct が必要です。

private suspend fun ZoneManagement.updateZone(
  zoneId: UShort,
  zone: ZoneManagementTrait.TwoDCartesianZoneStruct
) {
  // Execute the command to update the zone
  this.updateTwoDCartesianZone(zoneId = zoneId, zone = zone)
}

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

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

private suspend fun ZoneManagement.deleteZone(zoneId: UShort) {
  // Execute the command to remove the zone
  this.removeZone(zoneId = zoneId)
}

サウンド イベント トリガー

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

EventTriggerTypeEnum を使用した音声検出では、次のトリガータイプを使用できます。

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

音検出のステータスを確認する

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

Kotlin Flow を使用した Android 開発では、通常、HomeDevice から AvStreamAnalysis トレイトをオブザーブします。

// Example structure to store the
data class EventTriggerAttribute(val type: EventTriggerTypeEnum, val enabled: Boolean)

// 1. Obtain the trait flow from the device
private val avStreamAnalysisFlow: Flow<AvStreamAnalysis> =
  device.traitFromType(AvStreamAnalysis, CAMERA_TYPES.first { device.has(it) })

// 2. Map the flow to a list of sound event attributes
val soundEventTriggersState: Flow<List<EventTriggerAttribute>> =
  avStreamAnalysisFlow.map { trait ->
    // Get raw lists from the trait attributes
    val supported = trait.supportedEventTriggers ?: emptyList()
    val enabled = trait.enabledEventTriggers ?: emptyList()

    // Define sound-specific triggers to filter for
    val soundTypes = setOf(
      EventTriggerTypeEnum.Sound,
      EventTriggerTypeEnum.PersonTalking,
      EventTriggerTypeEnum.DogBark,
      EventTriggerTypeEnum.GlassBreak,
      EventTriggerTypeEnum.SmokeAlarm,
      EventTriggerTypeEnum.CoAlarm,
    )

    // Filter and associate status
    supported
      .filter { soundTypes.contains(it) }
      .map { type ->
        EventTriggerAttribute(
          type = type,
          enabled = enabled.contains(type)
        )
      }
  }

有効なトリガーのセットを更新する

有効なトリガーのセットを更新するには、EventTriggerEnablement 構造体のリストを受け取る SetOrUpdateEventDetectionTriggers コマンドを使用します。

private suspend fun AvStreamAnalysis.updateEventTriggers(
  eventTriggers: List<EventTriggerAttribute>
) {
  val toUpdate = eventTriggers.map {
    EventTriggerEnablement(
      eventTriggerType = it.type,
      enablementStatus = if (it.enabled) {
        EnablementStatusEnum.Enabled
      } else {
        EnablementStatusEnum.Disabled
      },
    )
  }

  // Execute the command on the device
  setOrUpdateEventDetectionTriggers(toUpdate)
}

録画モード

   Android 用サンプルアプリで実装   

RecordingMode トレイトは、カメラ デバイスとドアホン デバイスの動画と画像の録画動作を管理するためのインターフェースを提供します。連続録画、アクティビティ検出時の録画、録画の完全な無効化(ライブビューのみ)のいずれかを選択できます。

RecordingModeEnum は、使用可能な録音戦略を定義します。

モード 列挙値 説明
無効 Disabled 録画が完全に無効になります。主に以前のデバイスで使用されます。
CVR(連続録画) Cvr 動画は 24 時間 365 日録画されます。サブスクリプションが必要です(Google Home Premium など)。
EBR(アクティビティ検出時の録画) Ebr 録画はイベント(人物、動き)によってトリガーされます。動画の長さは、イベントの長さと定期購入のプランによって異なります。
ETR(イベント トリガー録画) Etr イベントによってトリガーされる短いプレビュー録画(10 秒など)。
ライブビュー LiveView 録画が無効になっているが、ユーザーはライブ ストリームにアクセスできる。
静止画像 Images アクティビティが発生すると、動画ではなくスナップショットが記録されます。

録画モードを確認する

現在の録画構成を表示するには、RecordingMode トレイトの属性を確認します。

// 1. Obtain the trait flow from the device
private val recordingModeTraitFlow: Flow =
    device.traitFromType(RecordingMode, CAMERA_TYPES.first { device.has(it) })

// 2. Map the flow to recording mode options
data class RecordingModeOptions(
    val recordingMode: RecordingModeTrait.RecordingModeEnum,
    val index: Int,
    val available: Boolean,
    val readableString: String,
)

private val recordingModeOptions: Flow<List> =
    recordingModeTraitFlow.map { trait ->
        val supported = trait.supportedRecordingModes?.map { it.recordingMode } ?: emptyList()
        val available = trait.availableRecordingModes?.map { it.toInt() } ?: emptyList()

        supported.withIndex().map { (index, mode) ->
            RecordingModeOptions(
                recordingMode = mode,
                index = index,
                available = available.contains(index),
                readableString = mode.toReadableString(),
            )
        }
    }

録画モードを変更する

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

選択したモードを更新するには、選択したモードのインデックスを渡して setSelectedRecordingMode 関数を使用します。

private suspend fun RecordingMode.updateRecordingMode(index: Int) {
    // Execute the command to update the selected mode
    this.setSelectedRecordingMode(index.toUByte())
}

その他の設定

その他のさまざまな設定は、Home API を介して制御できます。

ナイトビジョン機能をオンまたはオフにする

カメラのナイト ビジョンをオンまたはオフにするには、TriStateAutoEnum を使用して、組み込みの setNightVision Kotlin 関数を使用して CameraAvStreamManagement トレイトの nightVision 属性を更新します。

// Turn night vision on
cameraAvStreamManagement.update {
  setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.On)
}

// Turn night vision off
CameraAvStreamManagement.update {
  setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.Off)
}

ステータス LED の明るさを変更する

ステータス LED の明るさを変更するには、ThreeLevelAutoEnum を使用して、組み込みの setStatusLightBrightness Kotlin 関数を使用して CameraAvStreamManagement トレイトの statusLightBrightness 属性を更新します。

// Set the LED brightness to high
cameraAvStreamManagement.update {
  setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.High)
}

// Set the LED brightness to low
cameraAvStreamManagement.update {
  setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.Low)
}

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

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

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

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

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

cameraAvStreamManagement
  .update { setViewport(
    CameraAvStreamManagementTrait.ViewportStruct(
      x1 = horizontalRange.rangeStart.roundToInt().toUShort(),
      x2 = horizontalRange.rangeEnd.roundToInt().toUShort(),
      y1 = verticalRange.rangeStart.roundToInt().toUShort(),
      y2 = verticalRange.rangeEnd.roundToInt().toUShort(),
    )
) }

分析を有効または無効にする

各デバイスは、詳細な分析データを Google Home クラウドに送信するかどうかを個別に選択できます(Home API の Cloud Monitoring を参照)。

デバイスの分析を有効にするには、ExtendedGeneralDiagnosticsTraitanalyticsEnabled プロパティを true に設定します。analyticsEnabled を設定すると、別のプロパティ logUploadEnabled が自動的に true に設定され、分析ログファイルを Google Home クラウドにアップロードできるようになります。

// Enable analytics
extendedGeneralDiagnostics.update {
  setAnalyticsEnabled(true)
}

// Disable analytics
extendedGeneralDiagnostics.update {
  setAnalyticsEnabled(false)
}

トランスポートと録画の構成

このセクションでは、カメラのストリーミング品質とイベント トリガーに関連する設定について説明します。これらの設定は、PushAvStreamTransport トレイトによって管理されます。

転送設定を読み取る

このセクションでは、カメラまたはドアホン デバイスから現在の構成を取得する方法について説明します。PushAvStreamTransport トレイトを取得し、録画に使用される特定の接続を見つけて、帯域幅の品質、復帰感度、最大イベント長の現在の値を抽出します。

val trait: PushAvStreamTransport = device.getTrait(PushAvStreamTransport)
val connections = trait.findTransport().transportConfigurations

// Locate the connection designated for recording
val recordingConnection = connections.firstOrNull {
    it.transportOptions.getOrNull()?.streamUsage == StreamUsageEnum.Recording
}

val options = recordingConnection?.transportOptions?.getOrNull()

// 1. Bandwidth Quality (Video Stream ID)
val videoStreamId = options?.videoStreamId?.getOrNull()

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

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

転送設定を更新する

このセクションでは、トランスポート設定を変更する方法について説明します。新しい値を含む新しい TransportOptionsStruct を作成し、modifyPushTransport コマンドを使用して、これらの更新された設定をデバイスに送り返し、前のステップで見つかった録音接続に適用します。

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

val toUpdate = TransportOptionsStruct(
    videoStreamId = OptionalValue.present(2u), // e.g., Max Quality
    triggerOptions = TransportTriggerOptionsStruct(
        motionSensitivity = OptionalValue.present(5u), // e.g., Medium
        motionTimeControl = OptionalValue.present(
            TransportMotionTriggerTimeControlStruct(maxDuration = 30u)
        )
    )
)

if (recordingConnection != null) {
    trait.modifyPushTransport(
        connectionId = recordingConnection.connectionId,
        transportOptions = toUpdate
    )
}

帯域幅の品質を判断する

TransportOptionsStructvideoStreamId プロパティは、特定の動画ストリーム構成に対応します。

サポートされている動画ストリームを取得するには、VideoStreamStructs のリストである allocatedVideoStreams 属性を参照してください。デバイスの CameraAvStreamManagement トレイトから取得します。

デバイスの復帰感度を調整する

TransportTriggerOptionsStructmotionSensitivity プロパティは、次の値に対応します。

ラベル 値(UByte)
1u
5u
10u

最長アクティビティ時間を調整する

TransportMotionTriggerTimeControlStructmaxDuration プロパティは、次の期間(秒単位)に対応しています。

  • 10u15u30u60u120u180u

チャイムの設定

ドアホンのチャイムのさまざまな設定は、Home API を介して制御できます。

チャイムの音を変更する

ドアホンのチャイム音を変更するには、まず Chime トレイトの installedChimeSounds 属性を使用して、デバイスにインストールされているチャイム音のリストを取得します。

// Get a list of chimes and identify the currently selected one
private val doorbellChimeTraitFlow: Flow =
    device.traitFromType(Chime, GoogleDoorbellDevice)
val chimeSounds = doorbellChimeTraitFlow.first().installedChimeSounds ?: emptyList()

次に、組み込みの setSelectedChime Kotlin 関数を使用して、Chime トレイトの selectedChime 属性を更新します。

// Set the chime using the chimeId from the installed list
chimeSounds.firstOrNull { it.name == name }?.let { setSelectedChime(it.chimeId) }

外部チャイムを使用する

   Android 用サンプルアプリで実装   

ドアホンは、家の中に設置された機械式のベルなどの外部チャイムを使用するように構成できます。外部チャイムの損傷を防ぐため、ドアホンの設置時に設定する必要があります。

取り付けられている外部チャイムの種類を示すには、ExternalChimeType を使用して、組み込みの setExternalChime Kotlin 関数を使用して Chime トレイトの externalChime 属性を更新します。

// Indicate the external chime is mechanical
chime.update {
  setExternalChime(ChimeTrait.ExternalChimeType.Mechanical)
}

外部チャイムの音の長さを変更する

外部チャイムが鳴る時間(秒単位)は、Home API で構成できます。外部チャイムがチャイム音の長さをサポートしている場合、ユーザーはこれを設定できます。

ここで設定する値は、外部チャイム自体の仕様と、推奨されるチャイムの長さによって異なります。

外部チャイムの再生時間を変更するには、組み込みの setExternalChimeDurationSeconds Kotlin 関数を使用して、Chime トレイトの externalChimeDurationSeconds 属性を更新します。

// Change the external chime duration
chime.update {
  setExternalChimeDurationSeconds(newDuration.toUShort())
}

チャイムのテーマを有効にする

   Android 用サンプルアプリで実装   

一部のドアベルには、期間限定でユーザーが利用できるチャイムが用意されている場合があります。たとえば、祝日専用のチャイムなどです。これらはチャイムのテーマと呼ばれます。

ユーザーが利用できるチャイムのテーマを確認するには、タイムボックス フィルタを作成し、それを使用して ChimeThemes トレイトの getAvailableThemes() コマンドの結果をフィルタします。これにより、テーマ名を含む利用可能なテーマのリストが返されます。

次の例は、リストをフィルタする方法を示しています。現在の時刻がテーマの開始時刻と終了時刻(それぞれ startTimeSeconds 値と endTimeSeconds 値)の間にある場合、そのテーマは有効と見なされます。開始時刻が設定されていない場合、最初から有効と見なされます。終了時刻が設定されていない場合、無期限で有効になります。両方ともない場合、テーマは常に有効です。

// Get themes from the ChimeThemes trait
fun List<ChimeThemesTrait.ThemeStruct>.filterTimeboxedThemes():
    List<ChimeThemesTrait.ThemeStruct> {
  val now = timeSource.instant().epochSecond.toULong()
  return filter { chimeStruct: ChimeThemesTrait.ThemeStruct ->
    val startTime: ULong = chimeStruct.startTimeSeconds.getOrNull() ?: 0UL
    val endTime: ULong = chimeStruct.endTimeSeconds.getOrNull() ?: MAX_VALUE
    startTime <= now && now <= endTime
  }
}

val availableThemes =
  doorbellChimeThemesTraitFlow
    .first()
    .getAvailableThemes()
    .themes
    .filterTimeboxedThemes()

Christmas などの目的のテーマの名前を取得したら、ChimeThemes トレイトの setSelectedTimeboxedThemeName() 関数を使用して選択できます。

// Select a theme using the ChimeThemes trait
val themeToSelect = "Christmas"
if (themeToSelect in availableThemeNames) {
  doorbellChimeThemesTraitFlow.first().setSelectedTimeboxedThemeName(themeToSelect)
}

訪問客の通知の設定

ドアホンの訪問者通知設定をクエリして管理するには、Home API の VisitorAnnouncement トレイトを使用します。この特性は、誰かがドアホンを鳴らしたときに、Google スマート スピーカーやスマートディスプレイで訪問者の存在を通知するかどうかを制御します。

次の例は、訪問者のアナウンスが有効になっているかどうかを確認する方法と、この設定を更新する方法を示しています。

// Read the current visitor announcements state
val isEnabled = visitorAnnouncementTrait.visitorAnnouncementsEnabled

// Toggle the visitor announcements setting
visitorAnnouncementTrait.update {
    setVisitorAnnouncementsEnabled(true)
}