Leitfaden für Kamerageräte für Android

Der Gerätetyp „Kamera“ wird mit drei Attributen implementiert: PushAvStreamTransport, das die Übertragung von Audio- und Videostreams über pushbasierte Protokolle übernimmt, WebRtcLiveView, das die Steuerung von Livestreams und Talkback ermöglicht, und CameraSnapshot, das im Cache gespeicherte Vorschauschnappschüsse und Live-Schnappschüsse bereitstellt.

Prüfe immer, ob ein Gerät die Attribute und Befehle unterstützt, bevor du Funktionen verwendest oder versuchst, Attribute zu aktualisieren. Weitere Informationen findest du unter Geräte aufAndroidsteuern.

Gerätetyp für Home APIs Merkmale Kotlin-Beispiel-App Anwendungsfall

Kamera

GoogleCameraDevice

home.matter.6006.types.0158

Ein Gerät, das Standbilder oder Videos aufnimmt. Kameras können zugängliche Livestreams, Zweiwege-Audio oder Erkennungsereignisse bieten.

Erforderliche Attribute
     google PushAvStreamTransport
     google WebRtcLiveView

Kamera

Grundlegende Informationen zu einem Gerät abrufen

   In der Beispiel-App für Android implementiert   

Das Attribut BasicInformation enthält Informationen wie den Namen des Anbieters, die Anbieter-ID, die Produkt-ID, den Produktnamen (einschließlich Modellinformationen) und die Softwareversion für ein Gerät:

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

Seriennummer abrufen

Verwende den Befehl GetSerialNumber des Attributs ExtendedBasicInformation, um die Seriennummer des Geräts abzurufen. Im Beispiel wird die Seriennummer in einer Variablen namens serialNumber gespeichert:

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

Letzten Zeitpunkt des Cloud-Kontakts des Geräts abrufen

Wenn Sie herausfinden möchten, wann das Gerät zuletzt Kontakt mit der Cloud hatte, verwenden Sie das Attribut lastContactTimestamp des Attributs ExtendedGeneralDiagnostics:

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

Einstellungen für die Kamerahalterung

Das Attribut Mount enthält Einstellungen und Statusinformationen zur Kamerahalterung. Sie können Attribute wie den Bereitstellungsstatus, den Erkennungstyp und den Namen des Bereitstellungstyps lesen. Außerdem können Sie mit dem Merkmal Mount die Standardkonfiguration des Bereitstellungstyps überschreiben.

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

Verbindung eines Geräts prüfen

Die Konnektivität eines Geräts wird auf der Ebene des Gerätetyps geprüft, da einige Geräte mehrere Gerätetypen unterstützen. Der zurückgegebene Status ist eine Kombination der Verbindungsstatus aller Attribute auf diesem Gerät.

val cameraConnectivity = cameraDevice.metadata.sourceConnectivity.connectivityState

Der Status PARTIALLY_ONLINE kann bei gemischten Gerätetypen auftreten, wenn keine Internetverbindung besteht. Matter-Standard-Traits sind aufgrund des lokalen Routings möglicherweise noch online, cloudbasierte Traits sind jedoch offline.

IP-Adresse des Geräts abrufen

Verwende das Attribut networkInterfaces des Attributs GeneralDiagnostics, um die IP-Adresse des Geräts zu ermitteln. Die Adressen werden als Byte-Arrays zurückgegeben, die Sie in Standard-IPv4- oder IPv6-Strings formatieren können:

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

Livestream starten

   In der Beispiel-App für Android implementiert   

Wenn du einen Livestream starten möchtest, sende den SDP-String (Session Description Protocol) an die Methode startLiveView() des Attributs WebRtcLiveView. Diese gibt einen WebRtcLiveViewTrait.StartLiveViewCommand.Response mit drei Werten zurück:

  • Das SDP für die Sitzung.
  • Die Sitzungsdauer in Sekunden.
  • Die Sitzungs-ID, mit der die Sitzung verlängert oder beendet werden kann.
suspend fun getWebRtcLiveViewTrait(cameraDevice: HomeDevice) {
 return cameraDevice.type(GoogleCameraDevice).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)

Livestream verlängern

   In der Beispiel-App für Android implementiert   

Livestreams haben eine voreingestellte Dauer, nach der sie ablaufen. Wenn Sie die Dauer eines aktiven Streams verlängern möchten, senden Sie eine Verlängerungsanfrage mit der Methode 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 starten und beenden

   In der Beispiel-App für Android implementiert   

Wenn Sie TalkBack starten möchten, rufen Sie die Methode startTalkback() des Traits WebRtcLiveView auf. Verwenden Sie stopTalkback(), um die Wiedergabe zu beenden.

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

Livestream verwalten

Das Anpassen der Livestream-Qualität ist nützlich, um die Bandbreitennutzung basierend auf dem Anzeigekontext des Clients zu optimieren. Beispielsweise kann zu einer niedrigeren Auflösung gewechselt werden, wenn eine kleinere Vorschaukachel, eine Rasteransicht oder der Bild-im-Bild-Modus angezeigt wird.

Wenn du die Qualität dynamisch mit dem Attribut WebRtcLiveView änderst, wird die Auflösung der aktiven Livestream-Sitzung auf einem bestimmten Client verwaltet. Dies ist nicht dasselbe wie die Konfiguration einer geräteweiten Einstellung für die Bandbreitennutzung direkt auf dem Gerät, die sich auf alle gleichzeitigen Zuschauer und die Qualität der in der Cloud gespeicherten Videoaufnahmen auswirken würde.

Das folgende Beispiel zeigt, wie du die Livestream-Qualität für ein Gerät abrufen und aktualisieren kannst:

  • Unterstützte Qualitätsoptionen abrufen: Rufe die verfügbaren Streamingauflösungen ab, die vom Gerät unterstützt werden. Der Code fragt das Attribut supportedQualityHints des Attributs WebRtcLiveView im Ablauf des Gerätetyps ab und stellt die unterstützten Qualitäten als StateFlow mit einer Liste von QualityHint-Werten (z. B. QUALITY_HINT_SD, QUALITY_HINT_HD, QUALITY_HINT_FHD, QUALITY_HINT_QHD oder QUALITY_HINT_UHD) bereit.

  • Livestream-Qualität ändern: Wende eine ausgewählte QualityHint an, um die Streaming-Auflösung des aktiven Livestreams zu ändern (z. B. von Standard Definition zu High Definition). Die Funktion changeQuality löst das Livestreaming-Trait des Geräts auf und ruft changeLiveViewQuality mit dem aktiven mediaSessionId und der ausgewählten QualityHint-Konfiguration auf.

// Assuming you have a HomeDevice instance 'device'
val availableQualityHints: StateFlow<List> =
    device.type(GoogleCameraDevice)
        .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(GoogleCameraDevice).trait(WebRtcLiveView).first() ?: return
    try {
        trait.changeLiveViewQuality(mediaSessionId, qualityHint)
    } catch (e: Exception) {
        // Handle error
    }
}

Aufzeichnungsfunktion aktivieren und deaktivieren

Wenn du die Aufnahmefunktion der Kamera aktivieren möchtest, übergib TransportStatusEnum.Active an die Methode setTransportStatus() des Traits PushAvStreamTransport. Wenn Sie die Aufzeichnungsfunktion deaktivieren möchten, übergeben Sie TransportStatusEnum.Inactive. Im folgenden Beispiel werden diese Aufrufe in einem einzigen Aufruf zusammengefasst, bei dem ein Boolean verwendet wird, um die Aufnahmefunktion ein- oder auszuschalten:

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

Das Aktivieren oder Deaktivieren der Aufnahmefunktion der Kamera entspricht dem Ein- oder Ausschalten des Kameravideos. Wenn das Video einer Kamera eingeschaltet ist, zeichnet sie auf (für Ereignisse und zugehörige Clips).

Wenn die Aufnahmefunktion deaktiviert ist (die Kamera ist ausgeschaltet):

  • Die Kamera kann gemäß dem connectivityState des Gerätetyps weiterhin als online angezeigt werden.
  • Auf den Livestream kann nicht zugegriffen werden und die Kamera erkennt keine Cloud-Ereignisse.

Prüfen, ob die Aufzeichnungsfunktion aktiviert ist

Wenn du wissen möchtest, ob die Aufnahmefunktion einer Kamera aktiviert ist, prüfe, ob Verbindungen aktiv sind. Im folgenden Beispiel werden dazu zwei Funktionen definiert:

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

Eine weitere Möglichkeit besteht darin, die Funktion findTransport() mit einem Prädikat zu verwenden:

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

Kamera-Snapshots abrufen

   In der Beispiel-App für Android implementiert   

Verwende das Attribut CameraSnapshot, um statische Bild-Snapshots von einer Kamera abzurufen. Diese Snapshots sind in verschiedenen Szenarien hilfreich:

  • Als Platzhalter-Kachel in der Benutzeroberfläche, während ein WebRTC-Livestream geladen wird.
  • Als statisches Vorschaubild, das bei Nutzerinteraktion zu einem Livestream wird.
  • Als Hintergrund-Canvas zum Zeichnen und Konfigurieren benutzerdefinierter Alarmbereiche.

Das Attribut CameraSnapshot bietet zwei Möglichkeiten, Snapshots abzurufen, je nachdem, ob du einen im Cache gespeicherten Snapshot für schnelles Rendering oder einen On-Demand-Live-Snapshot benötigst.

Snapshot einer im Cache gespeicherten Vorschau abrufen

Ein Vorschauschnappschuss ist ein im Cache gespeichertes Bild, das das SDK abrufen kann, ohne die Kamera zu aktivieren. Dies ist die schnellste Methode, um ein statisches Bild abzurufen, und eignet sich ideal für Kameraübersichtsseiten oder Dashboard-Raster.

Wenn du den Vorschauschnappschuss abrufen möchtest, lies das Attribut 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
}

Je nach Kamerakonfiguration und Aktivität verweist die Vorschau-URL auf ein im Cache gespeichertes Bild, das aus aktuellen Videoaufnahmen (dem ersten I-Frame des neuesten Videofragments) generiert wurde, oder auf eine Momentaufnahme, die regelmäßig von der Kamera hochgeladen wird.

Um die Aktualität des Bildes anzugeben, bettet die Google Home-Cloud einen X-Home-Image-Captured-At-Header im bereitgestellten JPEG-/PNG-Bild ein, der im UTC-Format formatiert ist. Sie können diesen Header auf der Clientseite parsen, um das Alter des Snapshots in einer App anzuzeigen.

On-Demand-Live-Snapshot abrufen

Für User Journeys, die den aktuellen Livestream der Kamera erfordern, z. B. das Einrichten von Alarmbereichen, kannst du einen Live-Snapshot anfordern. Wenn du einen Live-Snapshot auslöst, wird die Kamera aktiviert, nimmt ein neues Bild auf und lädt es in die Cloud hoch.

Verwenden Sie den Befehl getLiveSnapshot(), um einen Live-Snapshot anzufordern:

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

Snapshot-Anfragen authentifizieren

   In der Beispiel-App für Android implementiert   

Alle Snapshot-URLs verweisen auf sichere Medien und erfordern ein OAuth 2.0-Token für den Bereich der Home APIs v2. Zum Herunterladen und Rendern der Bilder muss das OAuth-Token als Inhabertoken in den Authorization-Header Ihrer HTTP-Anfrage eingefügt werden.

Das folgende Beispiel zeigt, wie Sie eine sichere Netzwerkanfrage zum Herunterladen eines Snapshots konfigurieren:

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

Akkueinstellungen

Über die Home APIs können verschiedene Akkueinstellungen gesteuert werden.

Einstellung für die Akkunutzung festlegen

Mit der Energiebilanz kannst du den Kompromiss zwischen Akkulaufzeit und Leistung für ein Gerät konfigurieren. Sie können verschiedene Akkuprofile erstellen, z. B. „Erweitert“, „Ausgewogen“ und „Leistung“, und zwischen ihnen wechseln.

Diese Funktion wird durch Aktualisieren des Attributs currentEnergyBalance des Attributs EnergyPreference implementiert. Das Attribut akzeptiert einen Ganzzahlindex, der einem bestimmten Profil entspricht, das in der energyBalances-Liste des Geräts definiert ist (z. B. 0 für EXTENDED, 1 für BALANCED und 2 für PERFORMANCE).

Der Wert null für currentEnergyBalance gibt an, dass das Gerät ein benutzerdefiniertes Profil verwendet. Dies ist ein schreibgeschützter Status.

Im Folgenden finden Sie ein Beispiel für eine Struktur, die das Attribut currentEnergyBalance verwendet, gefolgt vom eigentlichen Code-Snippet, das das Attribut verwendet.

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

Automatischen Energiesparmodus aktivieren

Wenn du diese Funktion konfigurieren möchtest, aktualisiere das Attribut currentLowPowerModeSensitivity des Traits EnergyPreference. Dieses Attribut verwendet einen Index, um eine Empfindlichkeitsstufe auszuwählen, wobei 0 normalerweise für Disabled und 1 für Enabled oder Automatic steht.

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

Akkuladestatus abrufen

Verwende das Attribut batChargeState des Attributs PowerSource, um den aktuellen Ladestatus des Geräts abzurufen (wird geladen, vollständig geladen oder wird nicht geladen).

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

Akkustand abrufen

Verwende das Attribut batChargeLevel des Traits PowerSource, um den aktuellen Akkustand abzurufen. Die Stufe ist entweder OK, Warning (niedrig) oder 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"
}

Stromquelle abrufen

Verwende die Attribute BatPresent und wiredPresent des Traits PowerSource, um die Stromquelle des Geräts zu ermitteln.

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

Prüfen, ob die Batterie ausgetauscht werden muss

Das Attribut batReplaceability gibt an, ob der Akku nicht austauschbar, vom Nutzer austauschbar oder im Werk austauschbar ist.

Das Attribut batReplacementNeeded des Traits PowerSource gibt an, ob die Batterie ausgetauscht werden muss.

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

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

Wenn der Akku vom Nutzer ausgetauscht werden kann, wird er im batReplacementDescription beschrieben, einschließlich Informationen wie Formfaktor, chemische Zusammensetzung und bevorzugter Hersteller.

Audioeinstellungen

Über die Home APIs können verschiedene Audioeinstellungen gesteuert werden.

Mikrofon ein- und ausschalten

Wenn du das Mikrofon des Geräts ein- oder ausschalten möchtest, aktualisiere das Attribut microphoneMuted des Attributs CameraAvStreamManagement mit der integrierten Kotlin-Funktion setMicrophoneMuted:

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

Audioaufnahme ein- oder ausschalten

Wenn du die Audioaufnahme für das Gerät aktivieren oder deaktivieren möchtest, aktualisiere das Attribut recordingMicrophoneMuted des Traits CameraAvStreamManagement mit der integrierten Kotlin-Funktion setRecordingMicrophoneMuted:

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

Lautstärke des Lautsprechers anpassen

Wenn du die Lautsprecherlautstärke des Geräts anpassen möchtest, aktualisiere das Attribut speakerVolumeLevel des Attributs CameraAvStreamManagement mit der integrierten Kotlin-Funktion setSpeakerVolumeLevel:

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

Einstellungen für Alarmbereiche

   In der Beispiel-App für Android implementiert   

Das Attribut ZoneManagement bietet eine Schnittstelle zum Verwalten benutzerdefinierter Alarmbereiche auf Kamera- und Türklingelgeräten. Diese Bereiche werden verwendet, um die Ereigniserkennung (z. B. Bewegungen von Personen oder Fahrzeugen) auf bestimmte Bereiche im Sichtfeld des Geräts zu beschränken.

Alarmbereiche werden vom Nutzer in einer Partner-App konfiguriert. Er kann Bereiche über bestimmte Bereiche im Sichtfeld der Kamera zeichnen. Diese benutzerdefinierten Zonen werden dann in die von diesem Attribut verwendeten Strukturen übersetzt. Weitere Informationen zur Funktionsweise von Alarmbereichen findest du unter Alarmbereiche einrichten und verwenden.

Alarmbereiche werden normalerweise mit zweidimensionalen kartesischen Koordinaten definiert. Das Attribut stellt die TwoDCartesianVertexStruct für Eckpunkte und die TwoDCartesianZoneStruct für die Zonendefinition (Name, Eckpunkte, Farbe und Verwendung) bereit.

Alarmbereiche prüfen

Wenn du Alarmbereiche anzeigen lassen möchtest, prüfe das Attribut zones des Merkmals ZoneManagement.

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

Alarmbereich hinzufügen

Verwenden Sie zum Erstellen einer neuen Zone den Befehl createTwoDCartesianZone. Dieser Befehl verwendet ein TwoDCartesianZoneStruct, das den Namen, die Eckpunkte, die Farbe und die Verwendung der Zone definiert.

Im folgenden Beispiel wird gezeigt, wie Sie einen Bereich namens „Veranda“ mit vier Eckpunkten erstellen, der lachsfarben (#F439A0) ist und für die Bewegungserkennung verwendet wird.

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

Alarmbereich aktualisieren

Verwenden Sie zum Aktualisieren einer vorhandenen Zone den Befehl updateTwoDCartesianZone. Für diesen Befehl sind die zoneId und die aktualisierte TwoDCartesianZoneStruct erforderlich.

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

Alarmbereich löschen

Verwenden Sie zum Entfernen einer Zone den Befehl removeZone mit der spezifischen zoneId.

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

Geräuschereignis-Trigger

Das Attribut AvStreamAnalysis bietet eine Schnittstelle zum Verwalten von Auslösern für die Ereigniserkennung auf Kamera- und Türklingelgeräten. Während bildbasierte Auslöser (z. B. Personen oder Fahrzeuge) zonenspezifisch sein können, sind geräuschbezogene Auslöser in der Regel Konfigurationen auf Geräteebene.

Die folgenden Triggertypen sind für die Geräuscherkennung mit dem EventTriggerTypeEnum verfügbar:

Modus Enum-Wert Beschreibung
Ton Sound Allgemeine Geräuscherkennung.
Sprechende Person PersonTalking Erkennt Sprache.
Hundegebell DogBark Erkennt Hundelaute.
Glasbruch GlassBreak Erkennt das Geräusch von zerbrechendem Glas.
Rauchalarm SmokeAlarm Erkennt Rauchmelder, die oft am T3-Signalmuster (drei kurze Pieptöne gefolgt von einer Pause) zu erkennen sind.
Kohlenmonoxidalarm CoAlarm Erkennt Kohlenmonoxidalarme (CO), die normalerweise durch das T4-Muster (vier kurze Pieptöne, gefolgt von einer Pause) erkannt werden.

Status der Geräuscherkennung prüfen

Wenn du den aktuellen Status der Geräuscherkennung anzeigen möchtest, musst du prüfen, was das Gerät unterstützt und was von der Gerätehardware aktiviert wird. Die beiden zu prüfenden Attribute sind:

In der Android-Entwicklung mit Kotlin Flows beobachten Sie normalerweise das Merkmal AvStreamAnalysis aus dem HomeDevice.

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

Satz aktivierter Trigger aktualisieren

Verwenden Sie den Befehl SetOrUpdateEventDetectionTriggers, um die Gruppe der aktivierten Trigger zu aktualisieren. Dieser Befehl akzeptiert eine Liste von EventTriggerEnablement-Strukturen.

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

Aufnahmemodi

   In der Beispiel-App für Android implementiert   

Das Attribut RecordingMode bietet eine Schnittstelle zum Verwalten des Verhaltens bei der Video- und Bildaufzeichnung auf Kamera- und Türklingelgeräten. Nutzer können zwischen der Aufzeichnung rund um die Uhr, dem ereignisbasierten Videoverlauf oder der vollständigen Deaktivierung der Aufzeichnung (nur Live-Ansicht) wählen.

RecordingModeEnum definiert die verfügbaren Aufzeichnungsstrategien:

Modus Enum-Wert Beschreibung
Deaktiviert Disabled Die Aufzeichnung ist vollständig deaktiviert. Wird hauptsächlich von älteren Geräten verwendet.
CVR (Videoaufzeichnung rund um die Uhr) Cvr Videoaufzeichnung rund um die Uhr Hierfür ist ein Abo erforderlich (z. B. Google Home Premium).
EBR (ereignisbasierter Videoverlauf) Ebr Die Aufzeichnung wird durch Ereignisse (Person, Bewegung) ausgelöst. Die Videolänge hängt von der Dauer des Ereignisses und dem Abo ab.
ETR (Event Triggered Recording, ereignisgesteuerte Aufzeichnung) Etr Kurze Vorschauaufzeichnung (z. B. 10 Sekunden), die durch Ereignisse ausgelöst wird.
Live View LiveView Die Aufzeichnung ist deaktiviert, aber Nutzer können weiterhin auf den Livestream zugreifen.
Standbilder Images Wenn Ereignisse auftreten, werden Momentaufnahmen anstelle von Videos aufgezeichnet.

Aufnahmemodi prüfen

Wenn du die aktuelle Aufzeichnungskonfiguration anzeigen möchtest, prüfe die Attribute des Traits 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(),
            )
        }
    }

Aufnahmemodus ändern

Prüfen Sie vor dem Aktualisieren, ob der ausgewählte Index aus dem Attribut supportedRecordingModes im Attribut availableRecordingModes vorhanden ist.

Verwenden Sie zum Aktualisieren des ausgewählten Modus die Funktion setSelectedRecordingMode und übergeben Sie den Index des ausgewählten Modus:

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

Weitere Einstellungen

Über die Home APIs können verschiedene andere Einstellungen gesteuert werden.

Bildausrichtung ändern

Die Ausrichtung des Kamerabilds (Videos) kann gedreht werden. Das Video kann nur um 180 Grad gedreht werden.

Wenn du die Bildausrichtung der Kamera ändern möchtest, aktualisiere das Attribut imageRotation des Attributs CameraAvStreamManagement mit der integrierten Kotlin-Funktion setImageRotation:

// Change the camera's image orientation
val isRotated = false

cameraAvStreamManagement.update { setImageRotation(if (isRotated) 180.toUShort() else 0.toUShort()) }

Nachtsichtmodus aktivieren oder deaktivieren

Wenn du den Nachtsichtmodus für die Kamera ein- oder ausschalten möchtest, verwende TriStateAutoEnum, um das Attribut nightVision des Attributs CameraAvStreamManagement mit der integrierten Kotlin-Funktion setNightVision zu aktualisieren:

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

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

Helligkeit der Status-LED ändern

Wenn du die Helligkeit der Status-LED ändern möchtest, verwende ThreeLevelAutoEnum, um das Attribut statusLightBrightness des Attributs CameraAvStreamManagement mit der integrierten Kotlin-Funktion setStatusLightBrightness zu aktualisieren:

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

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

Kamera-Darstellungsbereich ändern

Das Sichtfeld der Kamera entspricht der Funktion „Zoomen und zuschneiden“, die im Hilfeartikel Video der Nest-Kamera zoomen und optimieren beschrieben wird.

Der Darstellungsbereich wird in einem ViewportStruct definiert, das vier Werte enthält, die als Koordinaten des Darstellungsbereichs verwendet werden. Die Koordinaten sind so definiert:

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

Die Werte für ViewportStruct hängen von der Benutzeroberfläche und der Kameraimplementierung einer App ab. Auf einer sehr einfachen Ebene aktualisierst du das Attribut viewport des Attributs CameraAvStreamManagement mit einem ViewportStruct, um den Darstellungsbereich des Kameravideos festzulegen. Verwende dazu die integrierte Kotlin-Funktion setViewport:

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

Analysen aktivieren oder deaktivieren

Für jedes Gerät kann einzeln festgelegt werden, ob detaillierte Analysedaten an die Google Home-Cloud gesendet werden sollen (siehe Cloud Monitoring für Home APIs).

Wenn Sie Analysen für ein Gerät aktivieren möchten, setzen Sie das Attribut analyticsEnabled von ExtendedGeneralDiagnosticsTrait auf true. Wenn du analyticsEnabled festlegst, wird eine andere Property, logUploadEnabled, automatisch auf true gesetzt. Dadurch können die Analyseloggdateien in die Google Home-Cloud hochgeladen werden.

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

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

Transport- und Aufzeichnungskonfigurationen

In diesem Abschnitt werden die Einstellungen für die Qualität des Kamerastreams und die Ereignisauslösung behandelt. Diese Einstellungen werden über das Attribut PushAvStreamTransport verwaltet.

Transporteinstellungen lesen

In diesem Abschnitt wird gezeigt, wie du die aktuelle Konfiguration einer Kamera oder Türklingel abrufst. Es ruft das Attribut PushAvStreamTransport ab, sucht die für die Aufzeichnung verwendete Verbindung und extrahiert dann die aktuellen Werte für die Bandbreitenqualität, die Empfindlichkeit für die Beendigung des Ruhemodus und die maximale Ereignislänge.

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

Transporteinstellungen aktualisieren

In diesem Abschnitt wird beschrieben, wie Sie die Transporteinstellungen ändern. Es wird ein neues TransportOptionsStruct mit den neuen Werten erstellt und dann der Befehl modifyPushTransport verwendet, um diese aktualisierten Einstellungen an das Gerät zurückzusenden und auf die im vorherigen Schritt gefundene Aufzeichnungsverbindung anzuwenden.

Verwenden Sie zum Ändern dieser Einstellungen den Befehl modifyPushTransport mit einem TransportOptionsStruct.

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

Bandbreitenqualität bestimmen

Das Attribut videoStreamId des TransportOptionsStruct entspricht einer bestimmten Videostream-Konfiguration.

Die unterstützten Videostreams findest du im Attribut allocatedVideoStreams, das eine Liste von VideoStreamStructs ist. aus dem Attribut CameraAvStreamManagement für das Gerät.

Empfindlichkeit für die Beendigung des Ruhemodus anpassen

Das Attribut motionSensitivity von TransportTriggerOptionsStruct entspricht den folgenden Werten:

Label Wert (UByte)
Niedrig 1u
Mittel 5u
Hoch 10u

Maximale Ereignisdauer anpassen

Das Attribut maxDuration von TransportMotionTriggerTimeControlStruct entspricht den folgenden Dauern (in Sekunden):

  • 10u, 15u, 30u, 60u, 120u, 180u

Gerät außer Betrieb nehmen

Wenn du eine Kamera aus einem Gebäude entfernen möchtest, rufe device.decommissionDevice() auf. Bei der Außerbetriebnahme wird dem Nutzer ein von Google verwalteter Bestätigungsbildschirm angezeigt, auf dem er darauf hingewiesen wird, dass der gesamte aufgezeichnete lückenlose Videoverlauf, der Ereignisverlauf, die Clips und die Daten der Gesichterdatenbank im gesamten Gebäude dauerhaft gelöscht werden.

Eine ausführliche Anleitung und Codebeispiele finden Sie unter Gerät entfernen.