El tipo de dispositivo Doorbell se implementa con dos rasgos: PushAvStreamTransportTrait, que controla el transporte de transmisiones de audio y video con protocolos basados en la transmisión, y WebRtcLiveViewTrait, que proporciona la capacidad de controlar transmisiones en vivo y la función de intercomunicador.
Siempre verifica la compatibilidad de los atributos y los comandos de un dispositivo antes de usar cualquier función o intentar actualizar los atributos. Consulta Cómo controlar dispositivos eniOS para obtener más información.
| Tipo de dispositivo de las APIs de Home | Rasgos | App de ejemplo de Swift | Caso de uso |
|---|---|---|---|
Timbre
Dispositivo que se acciona con un botón fuera de una puerta y que emite una señal audible o visual para solicitar la atención de una persona que se encuentra al otro lado de la puerta. Los timbres pueden incluir transmisiones en vivo accesibles, respuesta bidireccional o eventos de detección. |
Required Traits google PushAvStreamTransportTrait google WebRtcLiveViewTrait |
Timbre |
Cómo iniciar una transmisión en vivo
Para iniciar una transmisión en vivo, envía la cadena del Protocolo de descripción de sesión (SDP) al método startLiveView(offerSdp:) del rasgo WebRtcLiveViewTrait, que devuelve tres valores:
- Es el SDP de la sesión.
- Es la duración de la sesión en segundos.
- Es el ID de sesión, que se puede usar para extender o finalizar la sesión.
public func sendOffer(offerSdp: String) async throws
-> (answerSdp: String, mediaSessionId: String, liveViewDuration: TimeInterval)
{
do {
Logger.info("Sending StartLiveView command...")
let response = try await liveViewTrait.startLiveView(
offerSdp: offerSdp
)
Logger.info("Received StartLiveView response: \(response)")
return (
answerSdp: response.answerSdp,
mediaSessionId: response.mediaSessionId,
liveViewDuration: TimeInterval(response.liveSessionDurationSeconds)
)
} catch {
Logger.error("Failed to send StartLiveView command: \(error)")
throw error
}
}
Cómo extender una transmisión en vivo
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 extendLiveView(mediaSessionId:optionalArgsProvider:):
public func extendLiveView(mediaSessionId: String) async throws {
do {
Logger.info("Extending live view...")
let extendedDuration = try await liveViewTrait.extendLiveView(mediaSessionId: mediaSessionId)
Logger.info("Extended live view for \(extendedDuration.liveSessionDurationSeconds) seconds.")
} catch {
Logger.error("Failed to extend live view: \(error)")
throw error
}
}
Cómo iniciar y detener TalkBack
Para iniciar TalkBack, llama al método startTalkback(mediaSessionId:optionalArgsProvider:) del rasgo WebRtcLiveViewTrait.
Para detenerla, usa stopTalkback(mediaSessionId:).
public func toggleTwoWayTalk(isOn: Bool, mediaSessionId: String) async throws {
do {
Logger.info("Toggling twoWayTalk to \(isOn ? "ON" : "OFF")...")
if isOn {
try await liveViewTrait.startTalkback(mediaSessionId: mediaSessionId)
} else {
try await liveViewTrait.stopTalkback(mediaSessionId: mediaSessionId)
}
} catch {
throw HomeError.commandFailed("Failed to toggle twoWayTalk: \(error)")
}
}
Cómo habilitar e inhabilitar la capacidad de grabación
Para habilitar la capacidad de grabación de la cámara, pasa TransportStatusEnum.Active al método setTransportStatus(transportStatus:optionalArgsProvider:) del rasgo PushAvStreamTransportTrait. Para inhabilitar la capacidad de grabación, pasa TransportStatusEnum.Inactive.
En el siguiente ejemplo, incluimos estas llamadas en una sola llamada que usa un Boolean para activar o desactivar la capacidad de grabación:
public func toggleIsRecording(isOn: Bool) {
self.uiState = .loading
guard let pushAvStreamTransportTrait else {
Logger.error("PushAvStreamTransportTrait not found.")
return
}
Task {
do {
try await pushAvStreamTransportTrait.setTransportStatus(
transportStatus: isOn ? .active : .inactive)
if isOn {
do {
self.player = try self.createWebRtcPlayer()
} catch {
Logger.error("Failed to initialize WebRtcPlayer: \(error)")
self.uiState = .disconnected
return
}
await self.player?.initialize()
self.uiState = .live
} else {
self.player = nil
self.uiState = .off
}
} catch {
Logger.error("Failed to toggle onOff: \(error)")
}
}
}
Habilitar o inhabilitar la capacidad de grabación de la cámara es lo mismo que encender o apagar el video de la cámara. Cuando el video de una cámara está encendido, se 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 aún puede mostrarse como en línea según el
connectivityStatedel tipo de dispositivo. - No se puede acceder a la transmisión en vivo ni la cámara detecta eventos en la nube.
Comprueba si la capacidad 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 realizar esta acción:
public func isDeviceRecording() -> Bool {
guard let pushAvStreamTransportTrait else {
Logger.error("PushAvStreamTransportTrait not found.")
return false
}
guard
let hasActiveConnection =
pushAvStreamTransportTrait
.attributes
.currentConnections?
.contains(where: { $0.transportStatus == .active })
else {
return false
}
return hasActiveConnection
}
Configuración de audio
Se pueden controlar varios parámetros de configuración de audio de la cámara 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 del rasgo CameraAvStreamManagementTrait con la función setMicrophoneMuted integrada:
// Turn the device's microphone on or off
func setMicrophone(on: Bool) async {
do {
_ = try await self.cameraAvStreamManagementTrait?.update {
$0.setMicrophoneMuted(!on)
}
} catch {
// Error
}
}
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 del rasgo CameraAvStreamManagementTrait con la función setRecordingMicrophoneMuted integrada:
// Turn audio recording on or off for the device
func setAudioRecording(on: Bool) async {
do {
_ = try await self.cameraAvStreamManagementTrait?.update {
$0.setRecordingMicrophoneMuted(!on)
}
} catch {
// Error
}
}
Cómo ajustar el volumen de la bocina
Para ajustar el volumen del altavoz del dispositivo, actualiza el atributo speakerVolumeLevel del rasgo CameraAvStreamManagementTrait con la función setSpeakerVolumeLevel integrada:
// Adjust the camera speaker volume
func setSpeakerVolume(to value: UInt8) async {
do {
_ = try await cameraAvStreamManagementTrait.update {
$0.setSpeakerVolumeLevel(value)
}
} catch {
// Error
}
}
Otros parámetros de configuración
Se pueden controlar varios otros parámetros de configuración de la cámara 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 del rasgo CameraAvStreamManagementTrait con la función setNightVision integrada:
// Turn night vision on or off
func setNightVision(
to value: Google.CameraAvStreamManagementTrait.TriStateAutoEnum
) async {
do {
_ = try await cameraAvStreamManagementTrait.update {
$0.setNightVision(value)
}
} catch {
// Error
}
}
Cómo cambiar el brillo de la luz LED de estado
Para cambiar el brillo de la luz LED de estado, usa ThreeLevelAutoEnum para actualizar el atributo statusLightBrightness del rasgo CameraAvStreamManagementTrait con la función setStatusLightBrightness integrada:
// Set the LED brightness
func setStatusLightBrightness(
to value: Google.CameraAvStreamManagementTrait.ThreeLevelAutoEnum
) async {
do {
_ = try await cameraAvStreamManagementTrait.update {
$0.setStatusLightBrightness(value)
}
} catch {
// Error
}
}
Cómo cambiar el viewport de la cámara
El visor de la cámara es el mismo que la función Zoom and Crop que se describe en el artículo de asistencia técnica sobre cómo hacer zoom en el video de la cámara Nest y mejorar la detección.
La ventana gráfica se define en un ViewportStruct que contiene cuatro valores, los cuales se usan como las coordenadas de la ventana gráfica. 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 y la implementación de la cámara de una app. En un nivel muy básico, para configurar el viewport del video de la cámara, actualiza el atributo viewport del rasgo CameraAvStreamManagementTrait con un ViewportStruct, usando la función integrada setViewport.
func setCrop(x1: UInt16, y1: UInt16, x2: UInt16, y2: UInt16) {
let viewport = Google.CameraAvStreamManagementTrait.ViewportStruct(
x1: x1,
y1: y1,
x2: x2,
y2: y2
)
Task {
do {
try await cameraAvStreamManagementTrait.update {
$0.setViewport(viewport)
}
} catch {
// Error
}
}
}
Genera un TransportOptionsStruct
Algunos parámetros de configuración requieren modificaciones en las propiedades de un TransportOptionsStruct, que luego se pasa a las opciones de transporte de una conexión de transmisión. En el caso de Swift, esta estructura debe generarse antes de actualizar cualquier propiedad.
Usa esta función auxiliar para generar el struct que se usará con los siguientes cambios de configuración:
- Cómo ajustar la sensibilidad de activación del dispositivo
- Cómo ajustar la duración máxima de eventos
func getTransportOptions(
transportOptions: Google.PushAvStreamTransportTrait.TransportOptionsStruct,
wakeUpSensitivity: UInt8?,
maxEventLength: UInt32?
) async throws
-> Google.PushAvStreamTransportTrait.TransportOptionsStruct
{
var newMotionTimeControl:
Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct? = nil
if let maxEventLength {
guard let motionTimeControl = transportOptions.triggerOptions.motionTimeControl else {
throw HomeError.failedPrecondition(
// Error - cannot update max event length without motion time control
}
newMotionTimeControl =
Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct(
initialDuration: motionTimeControl.initialDuration,
augmentationDuration: motionTimeControl.augmentationDuration,
maxDuration: maxEventLength,
blindDuration: motionTimeControl.blindDuration
)
}
return Google.PushAvStreamTransportTrait.TransportOptionsStruct(
streamUsage: .recording,
videoStreamID: nil,
audioStreamID: nil,
tlsEndpointID: transportOptions.tlsEndpointID,
url: transportOptions.url,
triggerOptions: Google.PushAvStreamTransportTrait.TransportTriggerOptionsStruct(
triggerType: .motion,
motionZones: nil,
motionSensitivity: wakeUpSensitivity,
motionTimeControl: newMotionTimeControl,
maxPreRollLen: nil
),
ingestMethod: .cmafIngest,
containerOptions: Google.PushAvStreamTransportTrait.ContainerOptionsStruct(
containerType: .cmaf,
cmafContainerOptions: nil
),
expiryTime: nil
)
}
private func getRecordingConnection() async throws
-> Google.PushAvStreamTransportTrait.TransportConfigurationStruct?
{
guard let pushAvStreamTransportTrait else {
// Error - PushAvStreamTransport trait not available
return nil
}
let connections = try await pushAvStreamTransportTrait.findTransport().transportConfigurations
for connection in connections {
guard let transportOptions = connection.transportOptions,
transportOptions.streamUsage == .recording
else {
continue
}
return connection
}
return nil
}
Cómo ajustar la sensibilidad de activación del dispositivo
La sensibilidad de activación del dispositivo se usa para ahorrar batería, ya que disminuye el rango en el que el dispositivo puede detectar actividad y aumenta el tiempo de activación después de detectar esa actividad.
En las APIs de Home, esto se puede configurar con la propiedad motionSensitivity del objeto triggerOptions en el objeto transportOptions del dispositivo. Estas opciones se definen dentro del rasgo PushAvStreamTransportTrait para cada dispositivo.
La sensibilidad de activación solo se puede establecer en los siguientes valores:
- 1 = Baja
- 5 = Mediana
- 10 = Alto
El proceso de actualización consiste en encontrar la configuración de transporte para los flujos de grabación activos con el comando findTransport y, luego, modificar la configuración con el nuevo valor de sensibilidad con el comando modifyPushTransport.
El comando modifyPushTransport requiere que se pase el TransportOptionsStruct completo, por lo que primero debes copiar los valores existentes de la configuración actual. Consulta Genera un TransportOptionsStruct para una función de ayuda que haga esto.
func setWakeUpSensitivity(to value: UInt8) async {
do {
let connection = try await getRecordingConnection()
guard let connection,
let transportOptions = connection.transportOptions
else {
// Error - Transport options not available
return
}
guard transportOptions.triggerOptions.motionSensitivity != nil else {
// Error - Motion sensitivity not available to be updated for this device
return
}
try await pushAvStreamTransportTrait.modifyPushTransport(
connectionID: connection.connectionID,
transportOptions: self.getTransportOptions(
transportOptions: transportOptions,
wakeUpSensitivity: value,
maxEventLength: nil
)
)
} catch {
// Error
}
}
Cómo ajustar la duración máxima de eventos
La duración máxima del evento es el período durante el cual la cámara grabará un clip para un evento. A través de las APIs de Home, esto se puede configurar, por dispositivo, con las mismas longitudes que a través de Google Home app (GHA), en intervalos de segundos:
- 10 segundos
- 15 segundos
- 30 segundos
- 60 segundos (1 minuto)
- 120 segundos (2 minutos)
- 180 segundos (3 minutos)
En las APIs de Home, esto se puede configurar con la propiedad motionTimeControl del objeto triggerOptions en el objeto transportOptions del dispositivo. Estas opciones se definen dentro del rasgo PushAvStreamTransportTrait para cada dispositivo.
El proceso de actualización consiste en buscar la configuración de transporte para los flujos de grabación activos con el comando findTransport y, luego, modificar la configuración con el nuevo valor de duración del evento con el comando modifyPushTransport.
El comando modifyPushTransport requiere que se pase el TransportOptionsStruct completo, por lo que primero debes copiar los valores existentes de la configuración actual. Consulta Genera un TransportOptionsStruct para una función de ayuda que haga esto.
func setMaxEventLength(to value: UInt32) async {
do {
let connection = try await getRecordingConnection()
guard let connection,
let transportOptions = connection.transportOptions
else {
// Error - Transport options not available
return
}
guard transportOptions.triggerOptions.motionTimeControl != nil else {
// Error - Motion time control not available to be updated for this device
return
}
try await pushAvStreamTransportTrait.modifyPushTransport(
connectionID: connection.connectionID,
transportOptions: self.getTransportOptions(
transportOptions: transportOptions,
wakeUpSensitivity: nil,
maxEventLength: value
)
)
} catch {
// Error
}
}
Configuración de la campanilla
Se pueden controlar varios parámetros de configuración del timbre a través de las APIs de Home.
Cómo cambiar el sonido de la campanilla
Para cambiar el sonido del timbre, primero obtén la lista de sonidos de timbre instalados en el dispositivo con el atributo installedChimeSounds del rasgo ChimeTrait:
doorbellChimeTrait.attributes.installedChimeSounds?.compactMap { chimeSound in
return chimeSound.chimeID, chimeSound.name
}
Luego, actualiza el atributo selectedChime del rasgo ChimeTrait con la función integrada setSelectedChime:
func setDoorbellChime(chimeID: UInt8) async {
do {
_ = try await doorbellChimeTrait.update {
$0.setSelectedChime(chimeID)
}
} catch {
// Error
}
}
Cómo usar un timbre externo
El timbre se puede configurar para que use un timbre externo, 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 el timbre externo.
Para indicar qué tipo de timbre externo está instalado, usa ExternalChimeType para actualizar el atributo externalChime del rasgo ChimeTrait con la función setExternalChime integrada:
// Indicate the external chime is mechanical
func setExternalChime(to value: Google.ChimeTrait.ExternalChimeType) async {
do {
_ = try await doorbellChimeTrait.update {
$0.setExternalChime(value)
}
} catch {
// Error
}
}
Cómo cambiar la duración de la campanilla externa
La duración, en segundos, durante la que suena un timbre externo se puede configurar a través de las APIs de Home. Si el timbre externo admite una duración, es posible que el usuario quiera configurarla.
El valor establecido aquí depende de las especificaciones del timbre externo y de la duración recomendada del timbre.
Para cambiar la duración del timbre externo, actualiza el atributo externalChimeDurationSeconds del rasgo ChimeTrait con la función setExternalChimeDurationSeconds integrada:
// Change the external chime duration
func setExternalChimeDuration(to value: UInt16) async {
do {
_ = try await doorbellChimeTrait.update {
$0.setExternalChimeDuration(value)
}
} catch {
// Error
}
}