El tipo de dispositivo Doorbell se implementa con tres atributos:
PushAvStreamTransport,
que controla el transporte de transmisiones de audio y video con protocolos
basados en push,
WebRtcLiveView,
que proporciona la capacidad de controlar transmisiones en vivo y respuestas, y
CameraSnapshot,
que proporciona instantáneas de vista previa almacenadas en caché y capturas de instantáneas en vivo.
Siempre verifica la compatibilidad de atributos y comandos de un dispositivo antes de usar cualquier función o intentar actualizar los atributos. Consulta Controla dispositivos en Android para obtener más información.
| Tipo de dispositivo de las APIs de Home | Rasgos | App de ejemplo de Kotlin | Caso de uso |
|---|---|---|---|
|
Timbre
Es un dispositivo que se activa con un botón ubicado fuera de una puerta y que emite una señal audible o visual, que se usa para llamar la atención de una persona que se encuentra del otro lado de la puerta. Los timbres pueden incluir transmisiones en vivo accesibles, comunicación bidireccional o eventos de detección. |
Atributos obligatorios google PushAvStreamTransport google WebRtcLiveView |
Timbre |
Obtén información básica sobre un dispositivo
Implementado en la app de ejemplo para Android
El atributo BasicInformation
incluye información como el nombre del proveedor, el ID del proveedor, el ID del producto,
el nombre del producto (incluye información del modelo) y la versión de software de un dispositivo:
// 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}") }
Obtener número de serie
Para obtener el número de serie del dispositivo, usa el
comando GetSerialNumber de la
característica ExtendedBasicInformation.
En el ejemplo, se muestra cómo guardar el número de serie en una variable llamada serialNumber:
val basicInfo: ExtendedBasicInformation = device.getTrait(ExtendedBasicInformation) val serialNumber = basicInfo.getSerialNumber().serialNumber
Respuestas rápidas
La función de respuestas rápidas permite que el usuario envíe un mensaje predefinido a un dispositivo de timbre.
Esta función solo está disponible en dispositivos de timbre. La lista de mensajes predefinidos está disponible para la app del socio, que puede presentarlos al usuario para que elija uno. Los mensajes predefinidos no se pueden editar.
Las respuestas rápidas se implementan a través del atributo PresetMessage.
Cómo reproducir un mensaje predeterminado
Para reproducir un mensaje predeterminado, llama al método playPresetMessage y pásale uno de los valores de cadena que se encuentran en la propiedad availablePhraseTypes.
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}")
}
}
Configura el idioma hablado
Establece el idioma hablado activo de un dispositivo en una configuración regional específica (por ejemplo, "en_US") con el método setActiveLocale de la característica LocalizationConfiguration.
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) }
Obtén la hora más reciente de contacto del dispositivo con la nube
Para encontrar la hora más reciente en la que el dispositivo tuvo contacto con la nube, usa
el atributo lastContactTimestamp del
rasgo
ExtendedGeneralDiagnostics:
fun getLastContactTimeStamp(trait: ExtendedGeneralDiagnostics): java.time.Instant { val timestamp = trait.lastContactTimestamp return Instant.ofEpochSecond(timestamp.toLong()) }
Configuración del tipo de soporte de la cámara
El atributo Mount contiene la configuración del soporte de la cámara y la información de estado. Puedes leer atributos como
el estado de activación, el tipo de detección y el nombre del tipo de activación. Además,
puedes usar el atributo Mount para anular la configuración predeterminada del tipo de activación.
// 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) }
Verifica la conectividad de un dispositivo
La conectividad de un dispositivo se verifica a nivel del tipo de dispositivo, ya que algunos dispositivos admiten varios tipos. El estado que se devuelve es una combinación de los estados de conectividad de todos los rasgos de ese dispositivo.
Implementado en la app de ejemplo para Androidval doorbellConnectivity = doorbellDevice.metadata.sourceConnectivity.connectivityState
Se puede observar un estado de PARTIALLY_ONLINE en el caso de tipos de dispositivos mixtos cuando no hay conectividad a Internet.
Es posible que los rasgos estándar de Matter sigan en línea debido al enrutamiento local, pero los rasgos basados en la nube estarán sin conexión.
Obtén la dirección IP del dispositivo
Para encontrar la dirección IP del dispositivo, usa el atributo networkInterfaces del atributo GeneralDiagnostics. Las direcciones se devuelven como arrays de bytes, a los que puedes dar formato de
strings IPv4 o IPv6 estándar:
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()
Cómo iniciar una transmisión en vivo
Implementado en la app de ejemplo para Android
Para iniciar una transmisión en vivo, envía la cadena del protocolo de descripción de sesión (SDP) al método startLiveView() de la característica WebRtcLiveView, que devuelve un WebRtcLiveViewTrait.StartLiveViewCommand.Response que contiene tres valores:
- Es el SDP de la sesión.
- Es la duración de la sesión en segundos.
- El ID de la sesión, que se puede usar para extender o finalizar la sesión.
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)
Cómo extender una transmisión en vivo
Implementado en la app de ejemplo para Android
Las transmisiones en vivo tienen una duración predeterminada después de la cual vencen. Para extender la
duración de una transmisión activa, emite una solicitud de extensión con el método
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 }
Cómo iniciar y detener TalkBack
Implementado en la app de ejemplo para Android
Para iniciar TalkBack, llama al método startTalkback() del rasgo WebRtcLiveView. Para detenerla, usa
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) } }
Habilita e inhabilita la capacidad de grabación
Para habilitar la capacidad de grabación de la cámara, pasa TransportStatusEnum.Active al método setTransportStatus() de la característica PushAvStreamTransport. Para inhabilitar la capacidad de grabación, pásale TransportStatusEnum.Inactive.
En el siguiente ejemplo, unimos estas llamadas en una sola que usa un Boolean para activar o desactivar la capacidad de grabación:
// 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) } }
Habilitar o inhabilitar la capacidad de grabación de la cámara es lo mismo que activar o desactivar el video de la cámara. Cuando el video de una cámara está activado, está grabando (para fines de eventos y clips relacionados).
Cuando la capacidad de grabación está inhabilitada (el video de la cámara está desactivado):
- La cámara puede seguir mostrándose como en línea según el
connectivityStatedel tipo de dispositivo. - No se puede acceder a la transmisión en vivo, y la cámara no detecta ningún evento en la nube.
Verifica si la función de grabación está habilitada
Para determinar si la capacidad de grabación de una cámara está habilitada, verifica si hay conexiones activas. En el siguiente ejemplo, se definen dos funciones para hacerlo:
// 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 }
Otra forma de verificar es usar la función findTransport() con un predicado:
// Fetch the current connections suspend fun queryRecordModeState(trait: PushAvStreamTransport) { return trait.findTransport().let { it.transportConfigurations.any { it.transportStatus == TransportStatusEnum.Active } }
Recupera instantáneas de la cámara
Implementado en la app de ejemplo para Android
Usa el atributo CameraSnapshot para recuperar instantáneas de imágenes estáticas de una cámara.
Estas instantáneas son útiles en diferentes situaciones:
- Como un mosaico de marcador de posición en la IU mientras se carga una transmisión en vivo de WebRTC
- Como una imagen de vista previa estática que se actualiza a una transmisión en vivo cuando el usuario interactúa con ella
- Como lienzo de fondo para dibujar y configurar zonas de actividad personalizadas
El atributo CameraSnapshot ofrece dos formas de recuperar instantáneas, según si necesitas una instantánea almacenada en caché para una renderización rápida o una instantánea en vivo a pedido.
Obtén una instantánea de vista previa almacenada en caché
Una instantánea de vista previa es una imagen almacenada en caché que el SDK puede recuperar sin activar la cámara. Este es el método más rápido para recuperar una imagen estática y es ideal para las páginas de resumen de la cámara o las cuadrículas del panel.
Para obtener la instantánea de la vista previa, lee el atributo de rasgo 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 }
Según la configuración y la actividad de la cámara, la URL de vista previa apunta a una imagen almacenada en caché generada a partir de un video reciente (el primer fotograma I del fragmento de video más reciente) o una instantánea que la cámara sube periódicamente.
Para indicar la actualidad de la imagen, la nube de Google Home incorpora un encabezado X-Home-Image-Captured-At en la imagen JPEG o PNG que se entrega, con formato UTC. Puedes analizar este encabezado en el cliente para mostrar la antigüedad de la instantánea en una app.
Obtén una instantánea en vivo on demand
Para los recorridos del usuario que requieren la visualización en vivo actual de la cámara, como la configuración de las zonas de actividad, puedes solicitar una instantánea en vivo. Cuando se activa una instantánea en vivo, se le indica a la cámara que se active, capture un fotograma nuevo y lo suba a la nube.
Para solicitar una instantánea en vivo, usa el comando 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}") }
Autentica solicitudes de instantáneas
Implementado en la app de ejemplo para Android
Todas las URLs de instantáneas apuntan a contenido multimedia seguro y requieren un token de OAuth 2.0 para el
alcance de la versión 2 de las APIs de Home. Para descargar y renderizar las imágenes, el token de OAuth se debe
insertar como un token del portador en el encabezado Authorization de tu solicitud HTTP.
En el siguiente ejemplo, se muestra cómo configurar una solicitud de red segura para descargar una instantánea:
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() } }
Administra la transmisión en vivo
Ajustar la calidad de la transmisión en vivo es útil para optimizar el uso del ancho de banda según el contexto de visualización del cliente (por ejemplo, cambiar a una resolución más baja cuando se muestra una tarjeta de vista previa más pequeña, una vista de cuadrícula o el modo de pantalla en pantalla).
Cambiar la calidad de forma dinámica con el atributo WebRtcLiveView administra específicamente la resolución de la sesión de transmisión en vivo activa en un cliente en particular. No es lo mismo que configurar un parámetro de uso de ancho de banda para todo el dispositivo directamente en él, lo que afectaría a todos los usuarios simultáneos y la calidad de las grabaciones de video históricas guardadas en la nube.
En el siguiente ejemplo, se muestra cómo recuperar y actualizar la calidad de la transmisión en vivo de un dispositivo:
Recuperar las opciones de calidad compatibles: Obtén las resoluciones de transmisión disponibles compatibles con el dispositivo. El código consulta el atributo
supportedQualityHintsdel rasgoWebRtcLiveViewen el flujo del tipo de dispositivo y expone las calidades admitidas como unStateFlowque contiene una lista de valoresQualityHint(comoQUALITY_HINT_SD,QUALITY_HINT_HD,QUALITY_HINT_FHD,QUALITY_HINT_QHDoQUALITY_HINT_UHD).Cambiar la calidad de la transmisión en vivo: Aplica un
QualityHintseleccionado para cambiar la resolución de la transmisión en vivo activa (por ejemplo, cambiar de definición estándar a alta definición). La funciónchangeQualityresuelve el atributo de transmisión en vivo del dispositivo y llama achangeLiveViewQualitycon elmediaSessionIdactivo y la configuración deQualityHintelegida.
// 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 } }
Configuración de la batería
Se pueden controlar varios parámetros de configuración de la batería a través de las APIs de Home.
Establece la preferencia de uso de batería
Configurar el balance energético te permite establecer el equilibrio entre la duración de la batería y el rendimiento de un dispositivo. Puedes crear diferentes perfiles de batería, como "Extendido", "Equilibrado" y "Rendimiento", y alternar entre ellos.
Esta función se implementa actualizando el atributo currentEnergyBalance de la característica EnergyPreference. El atributo acepta un índice de número entero que corresponde a un perfil específico definido en la lista energyBalances del dispositivo (por ejemplo, 0 para EXTENDED, 1 para BALANCED y 2 para PERFORMANCE).
Un valor null para currentEnergyBalance indica que el dispositivo usa un perfil personalizado. Este es un estado de solo lectura.
A continuación, se muestra un ejemplo de una estructura que usará el atributo currentEnergyBalance, seguido del fragmento de código real que usa el atributo.
// 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)
Cómo activar el ahorro de batería automático
Para configurar esta función, actualiza el atributo currentLowPowerModeSensitivity de la característica EnergyPreference. Este atributo usa un índice
para seleccionar un nivel de sensibilidad, en el que 0 suele representar Disabled
y 1 representa Enabled o 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) } }
Cómo obtener el estado de carga de la batería
Para obtener el estado de carga actual del dispositivo (cargando, completamente cargado o sin cargar), usa el atributo batChargeState de la característica PowerSource.
// 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" }
Cómo obtener el nivel de batería
Para obtener el nivel de batería actual, usa el atributo batChargeLevel de la característica PowerSource. El nivel es OK, Warning (bajo) o 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" }
Obtén la fuente de alimentación
Para determinar la fuente de alimentación que usa el dispositivo,
usa los atributos
BatPresent
y
wiredPresent
del atributo
PowerSource.
val trait: PowerSource val isWired = trait.wiredPresent val hasBattery = trait.batPresent
Comprueba si es necesario reemplazar la batería
El atributo batReplaceability indica si la batería no se puede reemplazar, si el usuario puede reemplazarla o si se puede reemplazar en fábrica.
El atributo batReplacementNeeded del rasgo PowerSource te indica si se debe reemplazar la batería.
// Get the battery replacement status val batteryStatus = powerSourceTrait.batReplacementNeeded if (batteryStatus) { println("Replace the battery.") }
Cuando el usuario puede reemplazar la batería, el elemento batReplacementDescription la describe, incluida información como el factor de forma, la química y el fabricante preferido.
Configuración de audio
Se pueden controlar varios parámetros de configuración de audio a través de las APIs de Home.
Activar o desactivar el micrófono
Para activar o desactivar el micrófono del dispositivo, actualiza el atributo microphoneMuted de la característica CameraAvStreamManagement con la función integrada setMicrophoneMuted de Kotlin:
// Turn the device's microphone on or off suspend fun turnOffMicrophone(disableMicrophone: Boolean, trait: CameraAvStreamManagement) { trait.update { setMicrophoneMuted(disableMicrophone) } }
Cómo activar o desactivar la grabación de audio
Para activar o desactivar la grabación de audio en el dispositivo, actualiza el atributo recordingMicrophoneMuted de la característica CameraAvStreamManagement con la función integrada setRecordingMicrophoneMuted de Kotlin:
// Turn audio recording on or off for the device suspend fun turnOffAudioRecording(disableAudioRecording: Boolean, trait: CameraAvStreamManagement) { trait.update { setRecordingMicrophoneMuted(disableAudioRecording) } }
Cómo ajustar el volumen de la bocina
Para ajustar el volumen de la bocina del dispositivo, actualiza el atributo speakerVolumeLevel de la característica CameraAvStreamManagement con la función setSpeakerVolumeLevel integrada de Kotlin:
// Adjust the camera speaker volume suspend fun adjustSpeakerVolume(volume: Int, trait: CameraAvStreamManagement) { trait.update { setSpeakerVolumeLevel(volume.toUbyte()) } }
Configuración de las zonas de actividad
Implementado en la app de ejemplo para Android
La característica ZoneManagement proporciona una interfaz para administrar regiones de interés personalizadas (zonas de actividad) en dispositivos de cámara y timbre.
Estas zonas se usan para filtrar la detección de eventos (como el movimiento de personas
o vehículos) en áreas específicas dentro del campo visual del dispositivo.
El usuario configura las zonas de actividad en una aplicación de socio, lo que le permite dibujar zonas sobre áreas específicas en el campo visual de la cámara. Luego, estas zonas definidas por el usuario se traducen en las estructuras que usa este atributo. Para obtener más información sobre cómo funcionan las zonas de actividad, consulta Cómo configurar y usar las zonas de actividad.
Las zonas de actividad suelen definirse con coordenadas cartesianas 2D.
El atributo proporciona el
TwoDCartesianVertexStruct para los vértices y el
TwoDCartesianZoneStruct
para la definición de la zona (nombre, vértices, color y uso).
Cómo verificar las zonas de actividad
Para mostrar las zonas de actividad, verifica el atributo zones de la característica 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() }
Cómo agregar una zona de actividad
Para crear una zona nueva, usa el
comando createTwoDCartesianZone. Este comando toma un TwoDCartesianZoneStruct,
que define el nombre, los vértices, el color y el uso de la zona.
En el siguiente ejemplo, se muestra cómo crear una zona llamada "Front Porch" con cuatro vértices, de color salmón (#F439A0), que se usa para la detección de movimiento.
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}") } }
Cómo actualizar una zona de actividad
Para actualizar una zona existente, usa el
comando updateTwoDCartesianZone. Este comando requiere el zoneId y el TwoDCartesianZoneStruct actualizado.
private suspend fun ZoneManagement.updateZone( zoneId: UShort, zone: ZoneManagementTrait.TwoDCartesianZoneStruct ) { // Execute the command to update the zone this.updateTwoDCartesianZone(zoneId = zoneId, zone = zone) }
Cómo borrar una zona de actividad
Para quitar una zona, usa el comando
removeZone
con el zoneId específico.
private suspend fun ZoneManagement.deleteZone(zoneId: UShort) { // Execute the command to remove the zone this.removeZone(zoneId = zoneId) }
Activadores de eventos de sonido
La característica AvStreamAnalysis proporciona una interfaz para administrar los activadores de detección de eventos en dispositivos de cámara y timbre. Si bien los activadores basados en la visión
(como personas o vehículos) pueden ser específicos de una zona, los activadores relacionados con el sonido
suelen ser parámetros de configuración a nivel del dispositivo.
Los siguientes tipos de activadores están disponibles para la detección de sonido con el
EventTriggerTypeEnum:
| Modo | Valor enumerado | Descripción |
|---|---|---|
| Sonido | Sound |
Detección de sonido general. |
| Persona que habla | PersonTalking |
Detecta voz. |
| Ladrido de perro | DogBark |
Detecta vocalizaciones caninas. |
| Rotura de vidrio | GlassBreak |
Detecta el sonido de rotura de vidrio. |
| Alarma de humo | SmokeAlarm |
Detecta alarmas de humo, que suelen reconocerse por el patrón audible T3 (tres pitidos cortos seguidos de una pausa). |
| alarma de monóxido de carbono | CoAlarm |
Detecta alarmas de monóxido de carbono (CO), que suelen reconocerse por el patrón audible T4 (cuatro pitidos cortos seguidos de una pausa). |
Cómo verificar el estado de la detección de sonido
Para mostrarle al usuario el estado actual de la detección de sonido, debes verificar qué admite el dispositivo y qué habilita su hardware. Los dos atributos que se deben verificar son los siguientes:
En el desarrollo para Android con flujos de Kotlin, por lo general, observarías el atributo AvStreamAnalysis de 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) ) } }
Actualiza el conjunto de activadores habilitados
Para actualizar el conjunto de activadores habilitados, usa el comando
SetOrUpdateEventDetectionTriggers, que toma una lista de estructuras 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) }
Modos de grabación
Implementado en la app de ejemplo para Android
La característica RecordingMode proporciona una interfaz para administrar el comportamiento de grabación de video y de imágenes en dispositivos de cámara y timbre. Permite
que los usuarios elijan entre la grabación continua, la grabación basada en eventos
o la inhabilitación total de la grabación (solo visualización en vivo).
RecordingModeEnum
define las estrategias de grabación disponibles:
| Modo | Valor enumerado | Descripción |
|---|---|---|
| Inhabilitada | Disabled |
La grabación está completamente inhabilitada. Se usa principalmente en dispositivos heredados. |
| CVR (grabación de video continua) | Cvr |
El video se graba las 24 horas, todos los días. Requiere una suscripción (por ejemplo, Google Home Premium. |
| EBR (grabación basada en eventos) | Ebr |
La grabación se activa por eventos (persona, movimiento). La duración del video depende de la duración del evento y de la suscripción. |
| ETR (grabación activada por eventos) | Etr |
Grabación de vista previa corta (por ejemplo, 10 segundos) activada por eventos |
| Live View | LiveView |
La grabación está inhabilitada, pero los usuarios aún pueden acceder a la transmisión en vivo. |
| Imágenes fijas | Images |
Se graban instantáneas en lugar de videos cuando ocurren eventos. |
Verifica los modos de grabación
Para mostrar la configuración de grabación actual, verifica los atributos
del rasgo RecordingMode:
supportedRecordingModes: Todos los modos potencialesavailableRecordingModes: Modos seleccionablesselectedRecordingMode: Es el modo activo.
// 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(), ) } }
Cómo cambiar el modo de grabación
Antes de actualizar, asegúrate de que el índice elegido del atributo supportedRecordingModes esté presente en el atributo availableRecordingModes.
Para actualizar el modo seleccionado, usa la
función setSelectedRecordingMode y pasa el índice del modo elegido:
private suspend fun RecordingMode.updateRecordingMode(index: Int) { // Execute the command to update the selected mode this.setSelectedRecordingMode(index.toUByte()) }
Otros parámetros de configuración
Se pueden controlar varios parámetros de configuración más a través de las APIs de Home.
Cómo activar o desactivar la visión nocturna
Para activar o desactivar la visión nocturna de la cámara, usa TriStateAutoEnum para actualizar el atributo nightVision de la característica CameraAvStreamManagement con la función integrada de Kotlin setNightVision:
// Turn night vision on cameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.On) } // Turn night vision off CameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.Off) }
Cómo cambiar el brillo de la luz de estado LED
Para cambiar el brillo del LED de estado, usa ThreeLevelAutoEnum para actualizar el atributo statusLightBrightness de la característica CameraAvStreamManagement con la función integrada de 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) }
Cómo cambiar el viewport de la cámara
El viewport de la cámara es el mismo que el de la función Zoom and Crop que se describe en el artículo de ayuda Cómo acercar y mejorar el video de la cámara Nest.
El viewport se define en un ViewportStruct que contiene cuatro valores, que
se usan como las coordenadas del viewport. Las coordenadas se definen de la siguiente manera:
(x1,y1) -- (x2,y1) | | (x1,y2) -- (x2,y2)
La determinación de los valores de ViewportStruct depende de la IU de la app y de la implementación de la cámara. En un nivel muy básico, para establecer el viewport del video de la cámara, actualiza el atributo viewport de la característica CameraAvStreamManagement con un ViewportStruct, usando la función integrada setViewport de Kotlin:
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(), ) ) }
Habilita o inhabilita las estadísticas
Cada dispositivo puede aceptar de forma individual enviar datos de estadísticas detallados a la nube de Google Home (consulta Cloud Monitoring para las APIs de Home).
Para habilitar las estadísticas de un dispositivo, establece la propiedad analyticsEnabled de ExtendedGeneralDiagnosticsTrait en true. Cuando configuras analyticsEnabled,
otra propiedad, logUploadEnabled, se establece automáticamente en true, lo que
permite que los archivos de registro de estadísticas se suban a la nube de Google Home.
// Enable analytics extendedGeneralDiagnostics.update { setAnalyticsEnabled(true) } // Disable analytics extendedGeneralDiagnostics.update { setAnalyticsEnabled(false) }
Configuración de transporte y grabación
En esta sección, se abordan los parámetros de configuración relacionados con la calidad de la transmisión de la cámara y
la activación de eventos. Estos parámetros de configuración se administran con el atributo PushAvStreamTransport.
Leer la configuración de transporte
En esta sección, se muestra cómo recuperar la configuración actual de un dispositivo de cámara o timbre. Recupera el atributo PushAvStreamTransport,
busca la conexión específica que se usa para grabar y, luego, extrae
los valores actuales de la calidad del ancho de banda, la sensibilidad de activación
y la duración máxima del evento.
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
Actualiza la configuración de transporte
En esta sección, se muestra cómo cambiar la configuración de transporte.
Crea un TransportOptionsStruct nuevo que contiene los valores nuevos y,
luego, usa el comando modifyPushTransport para enviar estos parámetros de configuración actualizados
al dispositivo y aplicarlos a la conexión de grabación que se encontró
en el paso anterior.
Para modificar estos parámetros de configuración, usa el
comando modifyPushTransport con un 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 ) }
Determina la calidad del ancho de banda
La propiedad videoStreamId
de TransportOptionsStruct corresponde a una
configuración de transmisión de video específica.
Para obtener las transmisiones de video compatibles, consulta el atributo allocatedVideoStreams, que es una lista de VideoStreamStructs.
del atributo CameraAvStreamManagement del dispositivo.
Cómo ajustar la sensibilidad de activación del dispositivo
La propiedad motionSensitivity
de TransportTriggerOptionsStruct corresponde a los
siguientes valores:
| Etiqueta | Valor (UByte) |
|---|---|
| Baja | 1u |
| Medio | 5u |
| Alto | 10u |
Ajusta la duración máxima de los eventos
La propiedad maxDuration de TransportMotionTriggerTimeControlStruct corresponde a las siguientes duraciones (en segundos):
- 10u, 15u, 30u, 60u, 120u, 180u
Configuración de la campanilla
Se pueden controlar varios parámetros de configuración de la campanilla del timbre a través de las APIs de Home.
Cómo cambiar el sonido de la campanilla
Para cambiar el sonido de la campanilla del timbre, primero obtén la lista de sonidos de campanilla que están
instalados en el dispositivo con el
atributo installedChimeSounds
del atributo Chime:
// 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()
Luego, actualiza el atributo selectedChime de la característica Chime con la función integrada setSelectedChime de Kotlin:
// Set the chime using the chimeId from the installed list chimeSounds.firstOrNull { it.name == name }?.let { setSelectedChime(it.chimeId) }
Usa una campanilla externa
Implementado en la app de ejemplo para Android
El timbre se puede configurar para usar una campanilla externa, como una campana mecánica instalada dentro de la casa. Esto se debe configurar durante la instalación del timbre para evitar posibles daños en la campanilla externa.
Para indicar qué tipo de timbre externo está instalado, usa
ExternalChimeType
para actualizar el atributo
externalChime
del atributo Chime con la función integrada
setExternalChime de Kotlin:
// Indicate the external chime is mechanical chime.update { setExternalChime(ChimeTrait.ExternalChimeType.Mechanical) }
Cómo cambiar la duración de la campanilla externa
La duración, en segundos, que suena una campanilla externa se puede configurar a través de las APIs de Home. Si la campanilla externa admite una duración de la campanilla, es posible que el usuario quiera configurarla.
El valor que se establece aquí depende de las especificaciones de la campanilla externa y de la duración recomendada de la campanilla.
Para cambiar la duración de la campanilla externa, actualiza el atributo externalChimeDurationSeconds de la característica Chime con la función integrada de Kotlin setExternalChimeDurationSeconds:
// Change the external chime duration chime.update { setExternalChimeDurationSeconds(newDuration.toUShort()) }
Cómo habilitar un tema de campanilla
Implementado en la app de ejemplo para Android
Algunos timbres pueden tener campanadas que solo están disponibles para los usuarios durante un tiempo limitado. Por ejemplo, campanadas específicas para las festividades. Estos se denominan temas de campanilla.
Para ver qué temas de campanilla están disponibles para un usuario, crea un filtro de intervalo de tiempo
y úsalo para filtrar los resultados del
comando getAvailableThemes()
del atributo
ChimeThemes. Esto devuelve una lista de los temas disponibles, incluidos sus nombres.
En el siguiente ejemplo, se muestra cómo filtrar la lista.
Un tema se considera activo si la hora actual se encuentra dentro de sus horas de inicio y finalización (los valores startTimeSeconds y endTimeSeconds, respectivamente). Si no se establece una hora de inicio, se considera activa desde el
principio de los tiempos. Si no se establece una hora de finalización, seguirá activa
de forma indefinida. Si faltan ambos, el tema siempre estará activo.
// 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()
Una vez que tengas el nombre del tema que deseas, como Christmas, puedes seleccionarlo con la función setSelectedTimeboxedThemeName() en el atributo ChimeThemes:
// Select a theme using the ChimeThemes trait val themeToSelect = "Christmas" if (themeToSelect in availableThemeNames) { doorbellChimeThemesTraitFlow.first().setSelectedTimeboxedThemeName(themeToSelect) }
Configuración de anuncios de visitantes
Puedes consultar y administrar la configuración de los anuncios de visitantes para los timbres con el atributo VisitorAnnouncement de las APIs de Home. Este atributo controla si se anuncia la presencia de un visitante en las bocinas o pantallas inteligentes de Google cuando alguien toca el timbre.
En el siguiente ejemplo, se muestra cómo comprobar si los anuncios de visitantes están habilitados y cómo actualizar este parámetro de configuración:
// Read the current visitor announcements state val isEnabled = visitorAnnouncementTrait.visitorAnnouncementsEnabled // Toggle the visitor announcements setting visitorAnnouncementTrait.update { setVisitorAnnouncementsEnabled(true) }
Cómo retirar un dispositivo
Para quitar un timbre de una estructura, llama a device.decommissionDevice(). La baja muestra al usuario una
pantalla de confirmación administrada por Google en la que se advierte que se borrarán de forma permanente
todos los datos del historial de video continuo, el historial de eventos, los clips y la biblioteca de rostros conocidos
en toda la estructura.
Para obtener instrucciones detalladas y ejemplos de código, consulta Quita un dispositivo.