The Doorbell device type is implemented using two traits:
PushAvStreamTransport,
which handles audio and video stream transport using push-based protocols, and
WebRtcLiveView,
which provides the ability to control livestreams and talkback.
Always check for attribute and command support for a device prior to using any features or attempting to update attributes. See Control devices on Android for more information.
| Home APIs Device Type | Traits | Kotlin Sample App | Use Case |
|---|---|---|---|
|
Doorbell
A device actuated by a button outside a door that makes an audible and/or visual signal, used to request the attention of a person who is somewhere on the other side of the door. Doorbells may feature accessible livestreams, two-way talkback, or detection events. |
Required Traits google PushAvStreamTransport google WebRtcLiveView |
Doorbell |
Get basic information about a device
The BasicInformation
trait includes information like vendor name, vendor ID, product ID,
product name (includes model information), software version,
and the serial number for a device:
// 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}") println("serialNumber ${basicInformation.serialNumber}") }
Check connectivity for a device
Connectivity for a device is actually checked at the device type level because some devices support multiple device types. The state returned is a combination of the connectivity states for all traits on that device.
val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState
A state of PARTIALLY_ONLINE may be observed in the case
of mixed device types when there is no internet connectivity.
Matter standard traits may still be online due to local
routing, but cloud-based traits will be offline.
Start a livestream
To start a livestream, send the Session Description Protocol (SDP) string
to the
WebRtcLiveView
trait's
startLiveView() method, which returns a
WebRtcLiveViewTrait.StartLiveViewCommand.Response
containing three values:
- The SDP for the session.
- The session duration in seconds.
- The session ID, which may be used to extend or terminate the session.
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)
Extend a livestream
Livestreams have a preset duration after which they expire. To lengthen the
duration of an active stream, issue an extension request using the
WebRtcLiveView.extendLiveView()
method:
// 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 }
Start and stop talkback
To start talkback, call the
WebRtcLiveView
trait's startTalkback()
method. To stop, 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) } }
Enable and disable recording capability
To enable the camera's recording capability, pass
TransportStatusEnum.Active
to the
PushAvStreamTransport
trait's
setTransportStatus()
method. To disable the recording capability, pass it
TransportStatusEnum.Inactive.
In the following example, we wrap these calls in a single call that uses a
Boolean to toggle the recording capability:
// 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) } }
Enabling or disabling the camera's recording capability is the same as turning the camera video on or off. When a camera's video is on, it is recording (for purposes of events and related clips).
When the recording capability is disabled (the camera video is off):
- The camera can still show as online per the
connectivityStateof the device type. - The livestream cannot be accessed, nor does the camera detect any cloud events.
Check if recording capability is enabled
To determine if a camera's recording capability is enabled, check to see if any connections are active. The following example defines two functions to do this:
// 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 }
Another way to check is using the findTransport() function with a predicate:
// Fetch the current connections suspend fun queryRecordModeState(trait: PushAvStreamTransport) { return trait.findTransport().let { it.transportConfigurations.any { it.transportStatus == TransportStatusEnum.Active } }
Battery settings
Various battery settings can be controlled through the Home APIs.
Set the battery usage preference
Setting the energy balance lets you configure the tradeoff between battery life and performance for a device. You can create different battery profiles, such as "Extended," "Balanced," and "Performance," and switch between them.
This feature is implemented by updating the
currentEnergyBalance attribute
of the EnergyPreference
trait. The attribute accepts an integer
index that corresponds to a specific profile defined in the
device's energyBalances list (for example, 0 for EXTENDED,
1 for BALANCED, and 2 for PERFORMANCE).
A null value for currentEnergyBalance indicates the device is using a
custom profile. This is a read-only state.
The following shows an example of a structure that the currentEnergyBalance
attribute will use, followed by the actual code snippet that uses the attribute.
// 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)
Turn on automatic battery saver
To configure this feature, update the
currentLowPowerModeSensitivity attribute
of the EnergyPreference
trait. This attribute uses an index
to select a sensitivity level, where 0 typically represents Disabled
and 1 represents Enabled or 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) } }
Get the battery charging state
To get the device's current charging state (charging, fully charged, or not
charging), use the
batChargeState
attribute of the
PowerSource
trait.
// 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" }
Get the battery level
To get the current battery level, use the
batChargeLevel
attribute of the
PowerSource
trait. The level is either OK, Warning (low), or 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" }
Get the power source
To determine the power source the device is using,
use the BatPresent
and
wiredPresent
attributes of the
PowerSource trait.
val trait: PowerSource val isWired = trait.wiredPresent val hasBattery = trait.batPresent
Audio settings
Various audio settings can be controlled through the Home APIs.
Turn microphone on or off
To turn the device's microphone on or off, update the
microphoneMuted
attribute of the CameraAvStreamManagement trait using the built-in
setMicrophoneMuted Kotlin function:
// Turn the device's microphone on or off suspend fun turnOffMicrophone(disableMicrophone: Boolean, trait: CameraAvStreamManagement) { trait.update { setMicrophoneMuted(disableMicrophone) } }
Turn audio recording on or off
To turn audio recording on or off for the device, update the
recordingMicrophoneMuted
attribute of the CameraAvStreamManagement trait using the built-in
setRecordingMicrophoneMuted Kotlin function:
// Turn audio recording on or off for the device suspend fun turnOffAudioRecording(disableAudioRecording: Boolean, trait: CameraAvStreamManagement) { trait.update { setRecordingMicrophoneMuted(disableAudioRecording) } }
Adjust the speaker volume
To adjust the speaker volume for the device, update the
speakerVolumeLevel
attribute of the CameraAvStreamManagement trait using the built-in
setSpeakerVolumeLevel Kotlin function:
// Adjust the camera speaker volume suspend fun adjustSpeakerVolume(volume: Int, trait: CameraAvStreamManagement) { trait.update { setSpeakerVolumeLevel(volume.toUbyte()) } }
Other settings
Various other settings can be controlled through the Home APIs.
Turn night vision on or off
To turn night vision on or off for the camera, use TriStateAutoEnum
to update the
nightVision
attribute of the CameraAvStreamManagement trait using the built-in
setNightVision Kotlin function:
// Turn night vision on cameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.On) } // Turn night vision off CameraAvStreamManagement.update { setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.Off) }
Change the brightness of the status LED
To change the brightness of the status LED, use
ThreeLevelAutoEnum
to update the
statusLightBrightness
attribute of the CameraAvStreamManagement trait using the built-in
setStatusLightBrightness Kotlin function:
// Set the LED brightness to high cameraAvStreamManagement.update { setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.High) } // Set the LED brightness to low cameraAvStreamManagement.update { setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.Low) }
Change the camera viewport
The camera viewport is the same as the Zoom and Crop feature described in the Zoom and enhance Nest camera video support article.
The viewport is defined in a ViewportStruct that contains four values, which
are used as the coordinates of the viewport. The coordinates are defined as:
(x1,y1) -- (x2,y1) | | (x1,y2) -- (x2,y2)
Determining the values for the ViewportStruct depends on an app's UI and
camera implementation. At a very basic level, to set the viewport of the camera
video, update the
viewport
attribute of the CameraAvStreamManagement trait with a ViewportStruct, using
the built-in setViewport Kotlin function:
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(), ) ) }
Adjust the device wake-up sensitivity
The device's wake-up sensitivity is used to conserve battery by decreasing the range at which the device can sense activity and increasing the time to wake up after detecting that activity.
In the Home APIs, this can be set using the motionSensitivity property of the
triggerOptions in the device's transportOptions. These options are defined
within the PushAvStreamTransport trait for each device.
The wake-up sensitivity can only be set to the following values:
- 1 = Low
- 5 = Medium
- 10 = High
The process for updating is to find the transport configuration for active
recording streams using the
findTransport
command, then modify the configuration with the new sensitivity value using the
modifyPushTransport
command:
// Create a struct with the new wake-up sensitivity val toUpdate = TransportOptionsStruct( triggerOptions = TransportTriggerOptionsStruct( motionSensitivity = OptionalValue.present(wakeUpSensitivity.toUByte()) ) ) // Get the configurations for active connections val connections = pushAvStreamTransport.findTransport().transportConfigurations // Update all recording streams with the new transport options. for (connection in connections) { if (connection.transportOptions.getOrNull()?.streamUsage == StreamUsageEnum.Recording) { trait.modifyPushTransport( connectionId = connection.connectionId, transportOptions = toUpdate, ) } }
Adjust the maximum event length
The maximum event length is the length of time the camera will record a clip for an event. Through the Home APIs this can be configured, per device, to the same lengths as through the GHA, in intervals of seconds:
- 10 seconds
- 15 seconds
- 30 seconds
- 60 seconds (1 minute)
- 120 seconds (2 minutes)
- 180 seconds (3 minutes)
In the Home APIs, this can be set using the motionTimeControl property of the
triggerOptions in the device's transportOptions. These options are defined
within the PushAvStreamTransport trait for each device.
The process for updating is to find the transport configuration for active
recording streams using the
findTransport
command, then modify the configuration with the new event length value using the
modifyPushTransport
command:
// Create a struct with the new max event length // where maxDuration is the length in seconds val toUpdate = TransportOptionsStruct( triggerOptions = TransportTriggerOptionsStruct( motionTimeControl = OptionalValue.present( TransportMotionTriggerTimeControlStruct(maxDuration = it.toUInt()) ) ) ) // Get the configurations for active connections val connections = pushAvStreamTransport.findTransport().transportConfigurations // Update all recording streams with the new transport options. for (connection in connections) { if (connection.transportOptions.getOrNull()?.streamUsage == StreamUsageEnum.Recording) { trait.modifyPushTransport( connectionId = connection.connectionId, transportOptions = toUpdate, ) } }
Chime settings
Various doorbell chime settings can be controlled through the Home APIs.
Change the chime sound
To change the doorbell chime sound, first get the list of chime sounds that are
installed the device, using the
installedChimeSounds
attribute of the Chime trait:
// 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()
Then, update the
selectedChime
attribute of the Chime trait using the built-in setSelectedChime Kotlin
function:
// Set the chime using the chimeId from the installed list chimeSounds.firstOrNull { it.name == name }?.let { setSelectedChime(it.chimeId) }
Use an external chime
The doorbell can be configured to use an external chime, such as a mechanical bell installed inside the home. This should be configured during doorbell installation to avoid potential damage to the external chime.
To indicate what type of external chime is installed, use
ExternalChimeType
to update the
externalChime
attribute of the Chime trait using the built-in
setExternalChime Kotlin function:
// Indicate the external chime is mechanical chime.update { setExternalChime(ChimeTrait.ExternalChimeType.Mechanical) }
Change the external chime duration
The duration, in seconds, that an external chime rings can be configured through the Home APIs. If the external chime supports a chime duration, a user may want to configure this.
The value set here is dependent on the specifications of the external chime itself, and what its recommended chime duration is.
To change the external chime duration, update the
externalChimeDurationSeconds
attribute of the Chime trait using the built-in
setExternalChimeDurationSeconds Kotlin function:
// Change the external chime duration chime.update { setExternalChimeDurationSeconds(newDuration.toUShort()) }
Enable a chime theme
Some doorbells may have chimes that are only available to users for a limited time. For example, chimes specific to holidays. These are called chime themes.
To see which chime themes are available for a user, create a timebox filter
and use it to filter the results of the
getAvailableThemes()
command from the
ChimeThemes
trait. This returns a list of available themes, including theme names.
The following example shows how to filter the list.
A theme is considered active if the current time is within its
start and end times (the startTimeSeconds and endTimeSeconds values,
respectively). If a start time isn't set, it's considered active from the
beginning of time. If an end time isn't set, it continues to be active
indefinitely. If both are missing, the theme is always active.
// 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()
Once you have the name of the theme you want, such as Christmas, you can
select it using the setSelectedTimeboxedThemeName() function on the
ChimeThemes
trait:
// Select a theme using the ChimeThemes trait val themeToSelect = "Christmas" if (themeToSelect in availableThemeNames) { doorbellChimeThemesTraitFlow.first().setSelectedTimeboxedThemeName(themeToSelect) }