O tipo de dispositivo câmera é implementado usando três atributos:
PushAvStreamTransport,
que processa o transporte de stream de áudio e vídeo usando protocolos
baseados em push,
WebRtcLiveView,
que oferece a capacidade de controlar transmissões ao vivo e talkback, e
CameraSnapshot,
que fornece capturas de tela de visualização em cache e capturas de tela ao vivo.
Sempre verifique se o dispositivo é compatível com atributos e comandos antes de usar qualquer recurso ou tentar atualizar atributos. Consulte Controlar dispositivos no Android para mais informações.
| Tipo de dispositivo das APIs Home | Características | App de exemplo em Kotlin | Caso de uso |
|---|---|---|---|
|
Câmera
Um dispositivo que captura imagens estáticas ou vídeos. As câmeras podem ter transmissões ao vivo acessíveis, conversas bidirecionais ou eventos de detecção. |
Atributos obrigatórios google PushAvStreamTransport google WebRtcLiveView |
Câmera |
Receber informações básicas sobre um dispositivo
Implementado no app de exemplo para Android
O atributo BasicInformation
inclui informações como nome do fornecedor, ID do fornecedor, ID do produto,
nome do produto (inclui informações do modelo) e versão do software de um 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}") }
Encontrar o número de série
Para ver o número de série do dispositivo, use o
comando GetSerialNumber da
característica ExtendedBasicInformation.
O exemplo mostra como salvar o número de série em uma variável chamada serialNumber:
val basicInfo: ExtendedBasicInformation = device.getTrait(ExtendedBasicInformation) val serialNumber = basicInfo.getSerialNumber().serialNumber
Receber o horário mais recente de contato do dispositivo com a nuvem
Para encontrar o horário mais recente em que o dispositivo teve contato com a nuvem, use
o atributo lastContactTimestamp da
característica
ExtendedGeneralDiagnostics:
fun getLastContactTimeStamp(trait: ExtendedGeneralDiagnostics): java.time.Instant { val timestamp = trait.lastContactTimestamp return Instant.ofEpochSecond(timestamp.toLong()) }
Configurações do tipo de montagem de câmera
A característica Mount contém
as configurações de montagem da câmera e informações de status. É possível ler atributos como
o estado de montagem, o tipo de detecção e o nome do tipo de montagem. Além disso,
é possível usar o atributo Mount para substituir a configuração padrão do tipo de montagem.
// 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) }
Verificar a conectividade de um dispositivo
A conectividade de um dispositivo é verificada no nível do tipo de dispositivo, porque alguns dispositivos são compatíveis com vários tipos. O estado retornado é uma combinação dos estados de conectividade de todos os atributos desse dispositivo.
val cameraConnectivity = cameraDevice.metadata.sourceConnectivity.connectivityState
Um estado de PARTIALLY_ONLINE pode ser observado no caso
de tipos de dispositivos mistos quando não há conectividade com a Internet.
As características padrão do Matter ainda podem estar on-line devido ao roteamento local, mas as características baseadas na nuvem estarão off-line.
Encontrar o endereço IP do dispositivo
Para encontrar o endereço IP do dispositivo, use o atributo networkInterfaces do
trait
GeneralDiagnostics. Os endereços são retornados como matrizes de bytes, que podem ser formatadas como strings IPv4 ou IPv6 padrão:
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()
Iniciar uma transmissão ao vivo
Implementado no app de exemplo para Android
Para iniciar uma transmissão ao vivo, envie a string do Protocolo de Descrição de Sessão (SDP, na sigla em inglês)
para o método
startLiveView()
do atributo
WebRtcLiveView, que retorna um
WebRtcLiveViewTrait.StartLiveViewCommand.Response
com três valores:
- O SDP da sessão.
- A duração da sessão em segundos.
- O ID da sessão, que pode ser usado para estender ou encerrar a sessão.
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)
Estender uma transmissão ao vivo
Implementado no app de exemplo para Android
As transmissões ao vivo têm uma duração predefinida e expiram após esse período. Para aumentar a
duração de um stream ativo, emita uma solicitação de extensão usando o
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 }
Iniciar e interromper o TalkBack
Implementado no app de exemplo para Android
Para iniciar o talkback, chame o método
startTalkback()
da característica
WebRtcLiveView. Para interromper, use
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) } }
Gerenciar transmissão ao vivo
Ajustar a qualidade da transmissão ao vivo é útil para otimizar o uso da largura de banda com base no contexto de visualização do cliente (por exemplo, mudar para uma resolução mais baixa ao exibir um bloco de visualização menor, uma visualização em grade ou o modo picture-in-picture).
Mudar a qualidade dinamicamente usando o atributo
WebRtcLiveView
gerencia especificamente a resolução da sessão de transmissão ao vivo ativa
em um cliente específico. Isso não é o mesmo que definir uma configuração de uso de largura de banda para todo o dispositivo, o que afetaria todos os espectadores simultâneos e a qualidade das gravações de vídeo históricas salvas na nuvem.
O exemplo a seguir demonstra como recuperar e atualizar a qualidade da transmissão ao vivo de um dispositivo:
Recuperar opções de qualidade compatíveis: receba as resoluções de streaming disponíveis compatíveis com o dispositivo. O código consulta o atributo
supportedQualityHintsdo atributoWebRtcLiveViewno fluxo do tipo de dispositivo e expõe as qualidades compatíveis como umStateFlowque contém uma lista de valoresQualityHint(comoQUALITY_HINT_SD,QUALITY_HINT_HD,QUALITY_HINT_FHD,QUALITY_HINT_QHDouQUALITY_HINT_UHD).Mudar a qualidade da transmissão ao vivo: aplique um
QualityHintselecionado para mudar a resolução da transmissão ao vivo ativa (por exemplo, mudar de definição padrão para alta definição). A funçãochangeQualityresolve o atributo de transmissão ao vivo do dispositivo e chamachangeLiveViewQualitycom omediaSessionIdativo e a configuraçãoQualityHintescolhida.
// 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 } }
Ativar e desativar o recurso de gravação
Para ativar o recurso de gravação da câmera, transmita
TransportStatusEnum.Active
para o método
setTransportStatus()
da característica
PushAvStreamTransport. Para desativar o recurso de gravação, transmita
TransportStatusEnum.Inactive.
No exemplo a seguir, agrupamos essas chamadas em uma única chamada que usa um
Boolean para alternar o recurso de gravação:
// 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) } }
Ativar ou desativar a capacidade de gravação da câmera é o mesmo que ligar ou desligar o vídeo da câmera. Quando o vídeo de uma câmera está ativado, ela está gravando (para fins de eventos e clipes relacionados).
Quando o recurso de gravação está desativado (o vídeo da câmera está desligado):
- A câmera ainda pode aparecer como on-line de acordo com o
connectivityStatedo tipo de dispositivo. - Não é possível acessar a transmissão ao vivo, e a câmera não detecta eventos na nuvem.
Verificar se o recurso de gravação está ativado
Para determinar se o recurso de gravação de uma câmera está ativado, verifique se há conexões ativas. O exemplo a seguir define duas funções para fazer isso:
// 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 }
Outra maneira de verificar é usando a função findTransport() com um predicado:
// Fetch the current connections suspend fun queryRecordModeState(trait: PushAvStreamTransport) { return trait.findTransport().let { it.transportConfigurations.any { it.transportStatus == TransportStatusEnum.Active } }
Recuperar capturas de tela da câmera
Implementado no app de exemplo para Android
Use a característica CameraSnapshot para recuperar capturas de tela estáticas de uma câmera.
Esses snapshots são úteis em várias situações:
- Como um bloco de marcador de posição na interface enquanto uma transmissão ao vivo do WebRTC está carregando.
- Como uma imagem de prévia estática que se transforma em uma transmissão ao vivo quando o usuário interage com ela.
- Como uma tela de fundo para desenhar e configurar Zonas de Atividade personalizadas.
O atributo CameraSnapshot oferece duas maneiras de buscar capturas de tela, dependendo
se você precisa de uma captura de tela em cache para renderização rápida ou uma captura de tela ao vivo
sob demanda.
Receber um snapshot de visualização em cache
Uma captura de tela de prévia é uma imagem em cache que o SDK pode recuperar sem ativar a câmera. Esse é o método mais rápido para buscar uma imagem estática e é ideal para páginas de visão geral da câmera ou grades de painel.
Para receber o snapshot de prévia, leia o atributo de atributo 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 }
Dependendo da configuração e da atividade da câmera, o URL de visualização aponta para uma imagem em cache gerada de uma filmagem recente (o primeiro frame I do fragmento de vídeo mais recente) ou um snapshot enviado periodicamente pela câmera.
Para indicar a atualização da imagem, a nuvem do Google Home incorpora um cabeçalho X-Home-Image-Captured-At na imagem JPEG/PNG exibida, formatada em UTC. É possível analisar esse cabeçalho no
lado do cliente para exibir a idade do snapshot em um app.
Receber um snapshot em tempo real on demand
Para jornadas do usuário que exigem as imagens ao vivo atuais da câmera, como a configuração de Zonas de Atividade, é possível solicitar uma captura de tela ao vivo. Acionar uma captura de tela instantânea instrui a câmera a ativar, capturar um novo frame e fazer upload dele para a nuvem.
Para solicitar um snapshot em tempo real, use o 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}") }
Autenticar solicitações de snapshot
Implementado no app de exemplo para Android
Todos os URLs de captura de tela apontam para mídia segura e exigem um token OAuth 2.0 para o
escopo da v2 das APIs Home. Para baixar e renderizar as imagens, o token OAuth precisa ser
inserido como um token do portador no cabeçalho Authorization da solicitação HTTP.
O exemplo a seguir demonstra como configurar uma solicitação de rede segura para fazer o download de um snapshot:
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() } }
Configurações da bateria
Várias configurações de bateria podem ser controladas pelas APIs Home.
Definir a preferência de uso da bateria
A configuração do equilíbrio de energia permite definir a relação entre a duração da bateria e o desempenho de um dispositivo. É possível criar diferentes perfis de bateria, como "Estendido", "Equilibrado" e "Desempenho", e alternar entre eles.
Esse recurso é implementado atualizando o atributo
currentEnergyBalance
da característica
EnergyPreference. O atributo aceita um índice inteiro
que corresponde a um perfil específico definido na
lista energyBalances do dispositivo (por exemplo, 0 para EXTENDED,
1 para BALANCED e 2 para PERFORMANCE).
Um valor null para currentEnergyBalance indica que o dispositivo está usando um
perfil personalizado. Este é um estado somente leitura.
Veja a seguir um exemplo de estrutura que o atributo currentEnergyBalance
vai usar, seguido pelo snippet de código real que usa o 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)
Ativar a economia de bateria automática
Para configurar esse recurso, atualize o atributo
currentLowPowerModeSensitivity
da característica
EnergyPreference. Esse atributo usa um índice
para selecionar um nível de sensibilidade, em que 0 normalmente representa Disabled
e 1 representa Enabled ou 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) } }
Verificar o estado de carregamento da bateria
Para saber o estado de carregamento atual do dispositivo (carregando, totalmente carregado ou não
carregando), use o
atributo
batChargeState
da 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" }
Verificar o nível de bateria
Para conferir o Nível de bateria atual, use o atributo
batChargeLevel
da característica
PowerSource. O nível é OK, Warning (baixo) ou 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" }
Acessar a fonte de energia
Para determinar a fonte de energia que o dispositivo está usando,
use os atributos
BatPresent
e
wiredPresent
da característica
PowerSource.
val trait: PowerSource val isWired = trait.wiredPresent val hasBattery = trait.batPresent
Verificar se a bateria precisa ser trocada
O atributo batReplaceability indica se a bateria não pode ser substituída, se pode ser substituída pelo usuário ou se pode ser substituída pela fábrica.
O atributo
batReplacementNeeded
da característica
PowerSource
informa se a bateria precisa ser substituída.
// Get the battery replacement status val batteryStatus = powerSourceTrait.batReplacementNeeded if (batteryStatus) { println("Replace the battery.") }
Quando a bateria pode ser substituída pelo usuário, o
batReplacementDescription
a descreve, incluindo informações como formato, química e
fabricante preferencial.
Configurações de áudio
Várias configurações de áudio podem ser controladas pelas APIs Home.
Ativar ou desativar o microfone
Para ativar ou desativar o microfone do dispositivo, atualize o atributo
microphoneMuted
da característica CameraAvStreamManagement usando a função integrada
setMicrophoneMuted do Kotlin:
// Turn the device's microphone on or off suspend fun turnOffMicrophone(disableMicrophone: Boolean, trait: CameraAvStreamManagement) { trait.update { setMicrophoneMuted(disableMicrophone) } }
Ativar ou desativar a gravação de áudio
Para ativar ou desativar a gravação de áudio no dispositivo, atualize o atributo
recordingMicrophoneMuted
da característica CameraAvStreamManagement usando a função Kotlin
setRecordingMicrophoneMuted integrada:
// Turn audio recording on or off for the device suspend fun turnOffAudioRecording(disableAudioRecording: Boolean, trait: CameraAvStreamManagement) { trait.update { setRecordingMicrophoneMuted(disableAudioRecording) } }
Ajustar o volume do alto-falante
Para ajustar o volume do alto-falante do dispositivo, atualize o atributo
speakerVolumeLevel
da característica CameraAvStreamManagement usando a função integrada
setSpeakerVolumeLevel do Kotlin:
// Adjust the camera speaker volume suspend fun adjustSpeakerVolume(volume: Int, trait: CameraAvStreamManagement) { trait.update { setSpeakerVolumeLevel(volume.toUbyte()) } }
Configurações de Zonas de Atividade
Implementado no app de exemplo para Android
A característica ZoneManagement fornece uma interface para gerenciar regiões de interesse personalizadas (zonas de atividade) em dispositivos de câmera e campainha.
Essas zonas são usadas para filtrar a detecção de eventos (como movimento de pessoas ou veículos) para áreas específicas no campo de visão do dispositivo.
As zonas de atividade são configuradas pelo usuário em um aplicativo de parceiro, permitindo que ele desenhe zonas sobre áreas específicas no campo de visão da câmera. Essas zonas definidas pelo usuário são traduzidas para as estruturas usadas por essa característica. Para mais informações sobre como as Zonas de Atividade funcionam, consulte Configurar e usar as Zonas de Atividade.
As zonas de atividade geralmente são definidas usando coordenadas cartesianas 2D.
O atributo fornece o
TwoDCartesianVertexStruct para vértices e o
TwoDCartesianZoneStruct
para a definição da zona (nome, vértices, cor e uso).
Verificar as Zonas de Atividade
Para exibir as zonas de atividade, verifique o atributo
zones
da 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() }
Adicionar uma Zona de Atividade
Para criar uma zona, use o comando createTwoDCartesianZone. Esse comando usa um TwoDCartesianZoneStruct,
que define o nome, os vértices, a cor e o uso da zona.
O exemplo a seguir mostra como criar uma zona chamada "Front Porch" com quatro vértices, na cor salmão (#F439A0), usada para detecção de movimento.
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}") } }
Atualizar uma Zona de Atividade
Para atualizar uma zona, use o comando updateTwoDCartesianZone. Esse comando requer o zoneId e o
TwoDCartesianZoneStruct atualizado.
private suspend fun ZoneManagement.updateZone( zoneId: UShort, zone: ZoneManagementTrait.TwoDCartesianZoneStruct ) { // Execute the command to update the zone this.updateTwoDCartesianZone(zoneId = zoneId, zone = zone) }
Excluir uma Zona de Atividade
Para remover uma zona, use o comando
removeZone
com o zoneId específico.
private suspend fun ZoneManagement.deleteZone(zoneId: UShort) { // Execute the command to remove the zone this.removeZone(zoneId = zoneId) }
Gatilhos de detecção de som
O atributo AvStreamAnalysis fornece uma interface para gerenciar acionadores de detecção de eventos
em dispositivos de câmera e campainha. Enquanto os acionadores baseados em visão
(como pessoas ou veículos) podem ser específicos da zona, os acionadores relacionados ao som
normalmente são configurações no nível do dispositivo.
Os seguintes tipos de acionador estão disponíveis para detecção de som com a
EventTriggerTypeEnum:
| Modo | Valor de tipo enumerado | Descrição |
|---|---|---|
| Som | Sound |
Detecção de som geral. |
| Pessoa falando | PersonTalking |
Detecta fala. |
| Latido de cachorro | DogBark |
Detecta vocalizações caninas. |
| Vidro quebrando | GlassBreak |
Detecta o som de vidro quebrando. |
| Detector de fumaça | SmokeAlarm |
Detecta detectores de fumaça, geralmente reconhecidos pelo padrão sonoro T3 (três bipes curtos seguidos por uma pausa). |
| Alarme de monóxido de carbono | CoAlarm |
Detecta alarmes de monóxido de carbono (CO), normalmente reconhecidos pelo padrão sonoro T4 (quatro bipes curtos seguidos por uma pausa). |
Verificar o status da detecção de som
Para mostrar o estado atual da detecção de som ao usuário, verifique o que o dispositivo aceita e o que está ativado pelo hardware do dispositivo. Os dois atributos a serem verificados são:
No desenvolvimento para Android usando fluxos do Kotlin, normalmente você observa o
atributo AvStreamAnalysis do 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) ) } }
Atualizar o conjunto de gatilhos ativados
Para atualizar o conjunto de gatilhos ativados, use o comando
SetOrUpdateEventDetectionTriggers, que usa uma lista de estruturas 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 gravação
Implementado no app de exemplo para Android
A característica RecordingMode fornece uma interface para gerenciar o comportamento de gravação de vídeo e imagem em dispositivos de câmera e campainha. Ele permite
que os usuários escolham entre gravação contínua, gravação baseada em eventos
ou desativação total da gravação (somente imagens ao vivo).
O RecordingModeEnum
define as estratégias de gravação disponíveis:
| Modo | Valor de tipo enumerado | Descrição |
|---|---|---|
| Desativada | Disabled |
A gravação está totalmente desativada. Usado principalmente por dispositivos legados. |
| CVR (gravação contínua de vídeo) | Cvr |
O vídeo é gravado 24 horas por dia, 7 dias por semana. Requer uma assinatura (por exemplo, Google Home Premium. |
| EBR (gravação baseada em eventos) | Ebr |
A gravação é acionada por eventos (pessoa, movimento). A duração do vídeo depende da duração do evento e da assinatura. |
| ETR (gravação acionada por evento) | Etr |
Gravação de prévia curta (por exemplo, 10 segundos) acionada por eventos. |
| Live View | LiveView |
A gravação está desativada, mas os usuários ainda podem acessar a transmissão ao vivo. |
| Imagens estáticas | Images |
As capturas de tela são gravadas em vez de vídeos quando ocorrem eventos. |
Verificar modos de gravação
Para exibir a configuração de gravação atual, verifique os atributos
da característica RecordingMode:
supportedRecordingModes: todos os modos possíveisavailableRecordingModes: modos selecionáveisselectedRecordingMode: o modo ativo
// 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(), ) } }
Mudar o modo de gravação
Antes de atualizar, verifique se o índice escolhido do atributo supportedRecordingModes
está presente no atributo availableRecordingModes.
Para atualizar o modo selecionado, use a
função setSelectedRecordingMode, transmitindo o índice do modo escolhido:
private suspend fun RecordingMode.updateRecordingMode(index: Int) { // Execute the command to update the selected mode this.setSelectedRecordingMode(index.toUByte()) }
Outras configurações
Várias outras configurações podem ser controladas pelas APIs Home.
Mudar a orientação da imagem
A orientação da imagem da câmera (vídeo) pode ser girada. O vídeo só pode ser girado em 180 graus.
Para mudar a orientação da imagem da câmera, atualize o atributo
imageRotation
do atributo CameraAvStreamManagement usando a função Kotlin
setImageRotation integrada:
// Change the camera's image orientation val isRotated = false cameraAvStreamManagement.update { setImageRotation(if (isRotated) 180.toUShort() else 0.toUShort()) }
Ativar ou desativar a Visão Noturna
Para ativar ou desativar a visão noturna da câmera, use TriStateAutoEnum
para atualizar o atributo
nightVision
da característica CameraAvStreamManagement usando a função integrada
setNightVision do Kotlin:
// Turn night vision on cameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.On) } // Turn night vision off CameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.Off) }
Mudar o brilho do LED de status
Para mudar o brilho do LED de status, use
ThreeLevelAutoEnum
para atualizar o atributo
statusLightBrightness
da característica CameraAvStreamManagement usando a função integrada
setStatusLightBrightness do Kotlin:
// Set the LED brightness to high cameraAvStreamManagement.update { setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.High) } // Set the LED brightness to low cameraAvStreamManagement.update { setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.Low) }
Mudar a janela de visualização da câmera
A janela de visualização da câmera é igual ao recurso de zoom e corte descrito no artigo de suporte Zoom e modo Enhance no vídeo da câmera Nest.
A janela de visualização é definida em um ViewportStruct que contém quatro valores, que
são usados como as coordenadas da janela de visualização. As coordenadas são definidas como:
(x1,y1) -- (x2,y1) | | (x1,y2) -- (x2,y2)
A determinação dos valores para o ViewportStruct depende da interface do app e
da implementação da câmera. Em um nível muito básico, para definir a janela de visualização do vídeo da câmera, atualize o atributo viewport do atributo CameraAvStreamManagement com um ViewportStruct, usando a função integrada setViewport do 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(), ) ) }
Ativar ou desativar as análises
Cada dispositivo pode ativar individualmente o envio de dados de análise detalhados para a nuvem do Google Home (consulte Cloud Monitoring para APIs Home).
Para ativar as análises em um dispositivo, defina a propriedade
analyticsEnabled
do
ExtendedGeneralDiagnosticsTrait
como true. Quando você define analyticsEnabled,
outra propriedade, logUploadEnabled, é definida automaticamente como true, o que
permite que os arquivos de registro de análise sejam enviados para a nuvem do Google Home.
// Enable analytics extendedGeneralDiagnostics.update { setAnalyticsEnabled(true) } // Disable analytics extendedGeneralDiagnostics.update { setAnalyticsEnabled(false) }
Configurações de transporte e gravação
Esta seção aborda as configurações relacionadas à qualidade do stream da câmera e
ao acionamento de eventos. Essas configurações são gerenciadas pela característica
PushAvStreamTransport.
Ler configurações de transporte
Nesta seção, mostramos como recuperar a configuração atual de
uma câmera ou campainha. Ele busca a característica PushAvStreamTransport,
encontra a conexão específica usada para gravação e extrai
os valores atuais de qualidade da largura de banda, sensibilidade de ativação
e duração máxima do 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
Atualizar as configurações de transporte
Nesta seção, mostramos como mudar as configurações de transporte.
Ele cria um novo TransportOptionsStruct com os novos valores e
usa o comando modifyPushTransport para enviar essas configurações atualizadas
de volta ao dispositivo, aplicando-as à conexão de gravação encontrada
na etapa anterior.
Para modificar essas configurações, use o
comando modifyPushTransport com um 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 ) }
Determinar a qualidade da largura de banda
A propriedade videoStreamId
da TransportOptionsStruct corresponde a uma
configuração específica de stream de vídeo.
Para acessar os streams de vídeo compatíveis, consulte o atributo
allocatedVideoStreams,
que é uma lista de VideoStreamStructs.
do atributo CameraAvStreamManagement do dispositivo.
Ajustar a sensibilidade de ativação do dispositivo
A propriedade motionSensitivity
de TransportTriggerOptionsStruct corresponde aos
seguintes valores:
| Marcador | Valor (UByte) |
|---|---|
| Baixo | 1u |
| Médio | 5u |
| Alta | 10u |
Ajustar a duração máxima de eventos
A propriedade maxDuration
de TransportMotionTriggerTimeControlStruct
corresponde às seguintes durações (em segundos):
- 10u, 15u, 30u, 60u, 120u, 180u
Desativar um dispositivo
Para remover uma câmera de uma estrutura, chame
device.decommissionDevice(). A desativação mostra ao usuário uma
tela de confirmação gerenciada pelo Google avisando que todo o histórico de vídeo
24 horas, o histórico de eventos, os clipes e os dados da biblioteca de rostos conhecidos serão
excluídos permanentemente de toda a estrutura.
Para instruções detalhadas e exemplos de código, consulte Remover um dispositivo.