Przewodnik po urządzeniach z Androidem z funkcją kamery

Typ urządzenia Aparat jest implementowany za pomocą 2 cech: PushAvStreamTransport, która obsługuje transport strumieni audio i wideo za pomocą protokołów opartych na push, oraz WebRtcLiveView, która umożliwia sterowanie transmisjami na żywo i funkcją TalkBack.

Zanim zaczniesz korzystać z funkcji lub próbować aktualizować atrybuty, zawsze sprawdzaj, czy urządzenie obsługuje dany atrybut lub polecenie. Więcej informacji znajdziesz w artykule Sterowanie urządzeniami w Android.

Typ urządzenia w interfejsach Home API Cechy Przykładowa aplikacja w Kotlinie Przypadek użycia

Aparat

GoogleCameraDevice

home.matter.6006.types.0158

Urządzenie, które robi zdjęcia lub nagrywa filmy. Kamery mogą oferować dostępne transmisje na żywo, funkcję TalkBack lub wykrywanie zdarzeń.

Wymagane cechy
     google PushAvStreamTransport
     google WebRtcLiveView

Aparat

Pobieranie podstawowych informacji o urządzeniu

Cecha BasicInformation zawiera informacje takie jak nazwa dostawcy, identyfikator dostawcy, identyfikator produktu, nazwa produktu (w tym informacje o modelu) i wersja oprogramowania urządzenia:

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

Pobieranie numeru seryjnego

Aby uzyskać numer seryjny urządzenia, użyj GetSerialNumber polecenia cechy ExtendedBasicInformation. W tym przykładzie pokazujemy, jak zapisać numer seryjny w zmiennej o nazwie serialNumber:

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

Pobieranie najnowszej daty kontaktu urządzenia z chmurą

Aby znaleźć najnowszą datę kontaktu urządzenia z chmurą, użyj atrybutu lastContactTimestamp cechy ExtendedGeneralDiagnostics:

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

Sprawdzanie łączności urządzenia

Łączność urządzenia jest sprawdzana na poziomie typu urządzenia, ponieważ niektóre urządzenia obsługują wiele typów urządzeń. Zwracany stan jest połączeniem stanów łączności wszystkich cech na tym urządzeniu.

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

W przypadku mieszanych typów urządzeń, gdy nie ma połączenia z internetem, może pojawić się stan PARTIALLY_ONLINE. Cechy standardu Matter mogą być nadal online ze względu na routing lokalny, ale cechy oparte na chmurze będą offline.

Pobieranie adresu IP urządzenia

Aby znaleźć adres IP urządzenia, użyj atrybutu networkInterfaces cechy the GeneralDiagnostics. Adresy są zwracane jako tablice bajtów, które można sformatować do standardowych ciągów IPv4 lub 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()

Rozpoczynanie transmisji na żywo

Aby rozpocząć transmisję na żywo, wyślij ciąg SDP (Session Description Protocol) do WebRtcLiveView metody startLiveView() cechy, która zwraca WebRtcLiveViewTrait.StartLiveViewCommand.Response zawierający 3 wartości:

  • SDP sesji.
  • Czas trwania sesji w sekundach.
  • Identyfikator sesji, którego można użyć do przedłużenia lub zakończenia sesji.
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)

Przedłużanie transmisji na żywo

Transmisje na żywo mają ustawiony czas trwania, po którym wygasają. Aby wydłużyć czas trwania aktywnej transmisji, wyślij żądanie przedłużenia za pomocą WebRtcLiveView.extendLiveView() metody:

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

Rozpoczynanie i zatrzymywanie funkcji TalkBack

Aby rozpocząć korzystanie z funkcji TalkBack, wywołaj WebRtcLiveView metodę startTalkback() cechy. Aby zatrzymać, użyj 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)
  }
}

Włączanie i wyłączanie funkcji nagrywania

Aby włączyć funkcję nagrywania w kamerze, przekaż TransportStatusEnum.Active do PushAvStreamTransport cechy setTransportStatus() metody. Aby wyłączyć funkcję nagrywania, przekaż to TransportStatusEnum.Inactive. W tym przykładzie te wywołania są zawarte w jednym wywołaniu, które używa wartości Boolean do przełączania funkcji nagrywania:

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

Włączenie lub wyłączenie funkcji nagrywania w kamerze jest równoznaczne z włączeniem lub wyłączeniem obrazu z kamery. Gdy obraz z kamery jest włączony, kamera nagrywa (na potrzeby zdarzeń i powiązanych klipów).

Gdy funkcja nagrywania jest wyłączona (obraz z kamery jest wyłączony):

  • Kamera może nadal wyświetlać się jako online zgodnie z connectivityState typu urządzenia.
  • Nie można uzyskać dostępu do transmisji na żywo, a kamera nie wykrywa żadnych zdarzeń w chmurze.

Sprawdzanie, czy funkcja nagrywania jest włączona

Aby sprawdzić, czy funkcja nagrywania w kamerze jest włączona, sprawdź, czy są aktywne jakieś połączenia. W tym przykładzie definiujemy 2 funkcje, które to robią:

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

Innym sposobem sprawdzenia jest użycie funkcji findTransport() z predykatem:

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

Ustawienia baterii

Różnymi ustawieniami baterii można sterować za pomocą interfejsów Home API.

Ustawianie preferencji dotyczących wykorzystania baterii

Ustawienie bilansu energetycznego pozwala skonfigurować kompromis między żywotnością baterii a wydajnością urządzenia. Możesz utworzyć różne profile baterii, np. „Wydłużony”, „Zrównoważony” i „Wydajność”, i przełączać się między nimi.

Ta funkcja jest implementowana przez aktualizację atrybutu cechy .currentEnergyBalanceEnergyPreference Atrybut przyjmuje indeks całkowity, który odpowiada konkretnemu profilowi zdefiniowanemu na liście energyBalances urządzenia (np. 0 dla EXTENDED, 1 dla BALANCED i 2 dla PERFORMANCE).

Wartość null dla currentEnergyBalance oznacza, że urządzenie używa profilu niestandardowego. Jest to stan tylko do odczytu.

Poniżej znajdziesz przykład struktury, której będzie używać atrybut currentEnergyBalance, a następnie fragment kodu, który używa tego atrybutu.

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

Włączanie automatycznego oszczędzania baterii

Aby skonfigurować tę funkcję, zaktualizuj atrybut cechyEnergyPreference .currentLowPowerModeSensitivity Ten atrybut używa indeksu do wybrania poziomu czułości, gdzie 0 zwykle oznacza Disabled a 1 oznacza Enabled lub 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) }
}

Pobieranie stanu ładowania baterii

Aby uzyskać bieżący stan ładowania urządzenia (ładowanie, pełne naładowanie lub brak ładowania), użyj batChargeState atrybutu PowerSource cechy.

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

Pobieranie poziomu baterii

Aby uzyskać bieżący poziom baterii, użyj batChargeLevel atrybutu PowerSource cechy. Poziom może być OK, Warning (niski) lub 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"
}

Pobieranie źródła zasilania

Aby określić źródło zasilania, z którego korzysta urządzenie, użyj atrybutów BatPresent i wiredPresent cechy PowerSource.

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

Ustawienia dźwięku

Różnymi ustawieniami dźwięku można sterować za pomocą interfejsów Home API.

Włączanie i wyłączanie mikrofonu

Aby włączyć lub wyłączyć mikrofon urządzenia, zaktualizuj microphoneMuted atrybut cechy CameraAvStreamManagement za pomocą wbudowanej funkcji Kotlin setMicrophoneMuted:

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

Włączanie i wyłączanie nagrywania dźwięku

Aby włączyć lub wyłączyć nagrywanie dźwięku na urządzeniu, zaktualizuj recordingMicrophoneMuted atrybut cechy CameraAvStreamManagement za pomocą wbudowanej funkcji Kotlin setRecordingMicrophoneMuted:

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

Dostosowywanie głośności głośnika

Aby dostosować głośność głośnika urządzenia, zaktualizuj speakerVolumeLevel atrybut cechy CameraAvStreamManagement za pomocą wbudowanej funkcji Kotlin setSpeakerVolumeLevel:

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

Ustawienia miejsc aktywności

Cecha ZoneManagement udostępnia interfejs do zarządzania niestandardowymi obszarami zainteresowania (miejscami aktywności) na kamerach i dzwonkach do drzwi. Te miejsca służą do filtrowania wykrywania zdarzeń (np. ruchu osoby lub pojazdu) do określonych obszarów w polu widzenia urządzenia.

Miejsca aktywności są konfigurowane przez użytkownika w aplikacji partnera, co pozwala mu rysować miejsca na określonych obszarach w polu widzenia kamery. Te miejsca zdefiniowane przez użytkownika są następnie przekształcane w struktury używane przez tę cechę. Więcej informacji o tym, jak działają miejsca aktywności, znajdziesz w artykule Konfigurowanie i używanie miejsc aktywności.

Miejsca aktywności są zwykle definiowane za pomocą współrzędnych kartezjańskich 2D. Cecha udostępnia TwoDCartesianVertexStruct dla wierzchołków i TwoDCartesianZoneStruct dla definicji miejsca (nazwa, wierzchołki, kolor i użycie).

Sprawdzanie miejsc aktywności

Aby wyświetlić miejsca aktywności, sprawdź atrybut zones cechy 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()
  }

Dodawanie miejsca aktywności

Aby utworzyć nową strefę, użyj polecenia createTwoDCartesianZone. To polecenie przyjmuje TwoDCartesianZoneStruct, który definiuje nazwę, wierzchołki, kolor i użycie miejsca.

Poniższy przykład pokazuje, jak utworzyć strefę o nazwie „Front Porch” z czterema wierzchołkami, kolorem łososiowym (#F439A0) i używaną do wykrywania ruchu.

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

Aktualizowanie miejsca aktywności

Aby zaktualizować istniejące miejsce, użyj polecenia updateTwoDCartesianZone. To polecenie wymaga zoneId i zaktualizowanego TwoDCartesianZoneStruct.

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

Usuwanie miejsca aktywności

Aby usunąć strefę, użyj polecenia removeZone z konkretnym zoneId.

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

Aktywatory zdarzeń dźwiękowych

Cecha AvStreamAnalysis udostępnia interfejs do zarządzania aktywatorami wykrywania zdarzeń na kamerach i dzwonkach do drzwi. Aktywatory oparte na obrazie (np. osoby lub pojazdy) mogą być specyficzne dla miejsca, ale aktywatory związane z dźwiękiem są zwykle konfiguracjami na poziomie urządzenia.

W przypadku wykrywania dźwięku dostępne są te typy aktywatorów z EventTriggerTypeEnum:

Tryb Wartość typu enum Opis
Dźwięk Sound Ogólne wykrywanie dźwięku.
Ktoś coś mówi PersonTalking Wykrywa mowę.
Szczekanie psa DogBark Wykrywa wokalizacje psów.
Odgłos tłuczonego szkła GlassBreak Wykrywa dźwięk tłuczonego szkła.
Alarm z czujnika dymu SmokeAlarm Wykrywa alarmy z czujnika dymu, które często są rozpoznawane przez wzorzec dźwiękowy T3 (3 krótkie sygnały dźwiękowe, po których następuje przerwa).
Alarm z czujnika tlenku węgla CoAlarm Wykrywa alarmy z czujnika tlenku węgla, które zwykle są rozpoznawane przez wzorzec dźwiękowy T4 (4 krótkie sygnały dźwiękowe, po których następuje przerwa).

Sprawdzanie stanu wykrywania dźwięku

Aby wyświetlić użytkownikowi bieżący stan wykrywania dźwięku, musisz sprawdzić, co obsługuje urządzenie i co jest włączone przez sprzęt urządzenia. Należy sprawdzić te 2 atrybuty:

W przypadku programowania na Androida za pomocą Kotlin Flows zwykle obserwujesz cechę AvStreamAnalysis z 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)
        )
      }
  }

Aktualizowanie zestawu włączonych aktywatorów

Aby zaktualizować zestaw włączonych aktywatorów, użyj polecenia SetOrUpdateEventDetectionTriggers, które przyjmuje listę struktur EventTriggerEnablement.

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

Tryby nagrywania

Cecha RecordingMode udostępnia interfejs do zarządzania nagrywaniem filmów i obrazów na kamerach i dzwonkach do drzwi. Umożliwia użytkownikom wybór między nagrywaniem ciągłym, nagrywaniem zdarzeń lub całkowitym wyłączeniem nagrywania (tylko podgląd na żywo).

RecordingModeEnum definiuje dostępne strategie nagrywania:

Tryb Wartość typu enum Opis
Wyłączono Disabled Nagrywanie jest całkowicie wyłączone. Używane głównie przez starsze urządzenia.
CVR (Continuous Video Recording) Cvr Film jest nagrywany przez całą dobę. Wymaga subskrypcji (np. Google Home Premium).
EBR (Event Based Recording) Ebr Nagrywanie jest aktywowane przez zdarzenia (osoba, ruch). Długość wideo zależy od czasu trwania zdarzenia i subskrypcji.
ETR (Event Triggered Recording) Etr Krótkie nagranie podglądu (np. 10 sekund) aktywowane przez zdarzenia.
Widok na żywo LiveView Nagrywanie jest wyłączone, ale użytkownicy nadal mogą korzystać z transmisji na żywo.
Grafika Images Gdy występują zdarzenia, zamiast filmu nagrywane są migawki.

Sprawdzanie trybów nagrywania

Aby wyświetlić bieżącą konfigurację nagrywania, sprawdź atrybuty cechy 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(),
            )
        }
    }

Zmienianie trybu nagrywania

Zanim zaktualizujesz tryb, upewnij się, że wybrany indeks z atrybutu supportedRecordingModes jest obecny w atrybucie availableRecordingModes.

Aby zaktualizować wybrany tryb, użyj funkcji setSelectedRecordingMode, przekazując indeks wybranego trybu:

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

Inne ustawienia

Różnymi innymi ustawieniami można sterować za pomocą interfejsów Home API.

Zmienianie orientacji obrazu

Orientację obrazu z kamery (filmu) można obracać. Film można obracać tylko o 180 stopni.

Aby zmienić orientację obrazu z kamery, zaktualizuj imageRotation atrybut cechy CameraAvStreamManagement za pomocą wbudowanej funkcji Kotlin setImageRotation:

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

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

Włączanie i wyłączanie widzenia w nocy

Aby włączyć lub wyłączyć widzenie w nocy w kamerze, użyj TriStateAutoEnum aby zaktualizować nightVision atrybut cechy CameraAvStreamManagement za pomocą wbudowanej funkcji Kotlin setNightVision:

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

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

Zmienianie jasności diody stanu

Aby zmienić jasność diody stanu, użyj ThreeLevelAutoEnum , aby zaktualizować atrybut statusLightBrightness cechy CameraAvStreamManagement za pomocą wbudowanej funkcji Kotlin setStatusLightBrightness:

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

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

Zmienianie pola widzenia kamery

Widoczny obszar kamery jest taki sam jak funkcja powiększania i kadrowania opisana w artykule pomocy Powiększanie i ulepszanie obrazu z kamery Nest.

Pole widzenia jest zdefiniowane w ViewportStruct, który zawiera 4 wartości używane jako współrzędne pola widzenia. Współrzędne są zdefiniowane w ten sposób:

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

Określenie wartości dla ViewportStruct zależy od interfejsu aplikacji i implementacji kamery. Aby ustawić pole widzenia filmu z kamery , zaktualizuj viewport atrybut cechy CameraAvStreamManagement za pomocą ViewportStruct, używając wbudowanej funkcji Kotlin 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(),
    )
) }

Włączanie i wyłączanie statystyk

Każde urządzenie może indywidualnie wyrazić zgodę na wysyłanie szczegółowych danych analitycznych do chmury Google Home (więcej informacji znajdziesz w artykule Cloud Monitoring for Home APIs).

Aby włączyć statystyki na urządzeniu, ustaw właściwość analyticsEnabled cechy ExtendedGeneralDiagnosticsTrait na true. Gdy ustawisz analyticsEnabled, inna właściwość, logUploadEnabled, zostanie automatycznie ustawiona na true, co umożliwi przesyłanie plików dziennika statystyk do chmury Google Home.

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

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

Konfiguracje transportu i nagrywania

W tej sekcji omówimy ustawienia związane z jakością transmisji z kamery i aktywowaniem zdarzeń. Tymi ustawieniami zarządza cecha PushAvStreamTransport.

Odczytywanie ustawień transportu

W tej sekcji pokazujemy, jak pobrać bieżącą konfigurację z kamery lub dzwonka do drzwi. Pobiera cechę PushAvStreamTransport, znajduje konkretne połączenie używane do nagrywania, a następnie wyodrębnia bieżące wartości jakości przepustowości, czułości wybudzania i maksymalnego czasu trwania zdarzenia.

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

Aktualizowanie ustawień transportu

W tej sekcji pokazujemy, jak zmienić ustawienia transportu. Tworzy nowy TransportOptionsStruct zawierający nowe wartości, a następnie używa polecenia modifyPushTransport, aby wysłać te zaktualizowane ustawienia z powrotem do urządzenia, stosując je do połączenia nagrywania znalezionego w poprzednim kroku.

Aby zmodyfikować te ustawienia, użyj polecenia modifyPushTransport z 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
    )
}

Określanie jakości przepustowości

Właściwość videoStreamId cechy TransportOptionsStruct odpowiada konkretnej konfiguracji strumienia wideo.

Aby uzyskać obsługiwane strumienie wideo, zapoznaj się z allocatedVideoStreams atrybutem, który jest listą VideoStreamStructs. z cechy CameraAvStreamManagement urządzenia.

Dostosowywanie czułości wybudzania urządzenia

Właściwość motionSensitivity cechy TransportTriggerOptionsStruct odpowiada tym wartościom:

Etykieta Wartość (UByte)
Niski 1u
Średni 5u
Wysoki 10u

Dostosowywanie maksymalnego czasu trwania zdarzenia

Właściwość maxDuration cechy TransportMotionTriggerTimeControlStruct odpowiada tym czasom trwania (w sekundach):

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