<br />

The Camera device type is implemented using three traits:
[`PushAvStreamTransportTrait`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait),
which handles audio and video stream transport using push-based
protocols,
[`WebRtcLiveViewTrait`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/WebRtcLiveViewTrait),
which provides the ability to control livestreams and talkback, and
[`CameraSnapshotTrait`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/CameraSnapshotTrait),
which provides cached preview snapshots and live snapshot captures.

Always check for attribute and command support for a device prior to using any
features or attempting to update attributes. See [Control devices on
iOS](https://developers.home.google.com/apis/ios/device/control) for more
information.

> [!WARNING]
> **Warning:** These traits are restricted and not available for general use.

<br />


| Home APIs Device Type | Traits | Swift Sample App | Use Case |
|---|---|:---:|:---:|
| Camera `https://developers.home.google.com/reference/swift/GoogleHomeTypes/Structs/GoogleCameraDeviceType` `home.matter.6006.types.0158` A device that captures still images or video. Cameras may feature accessible livestreams, two-way talkback, or detection events. | Required Traits google [PushAvStreamTransportTrait](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait) google [WebRtcLiveViewTrait](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/WebRtcLiveViewTrait) | Yes | [Camera](https://developers.home.google.com/use-cases?device=camera) |

<br />

> [!NOTE]
> **Note:** The Automation API doesn't support these traits.

## Get basic information about a device

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

The [`BasicInformation`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/BasicInformationTrait)
trait includes information like vendor name, vendor ID, product ID,
product name (includes model information), and software version for a device:

```swift
let vendorName = basicInfoTrait.attributes.vendorName!
let vendorID = basicInfoTrait.attributes.vendorID!
let productID = basicInfoTrait.attributes.productID!
let productName = basicInfoTrait.attributes.productName!
let softwareVersion = basicInfoTrait.attributes.softwareVersion!
```

## Get serial number

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

To obtain the serial number of the device, use the
`GetSerialNumber` command of the
[`ExtendedBasicInformation`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/ExtendedBasicInformationTrait) trait.
The example shows saving the serial number in a variable named `serialNumber`:

```swift
// Assuming extendedBasicInformationTrait: Google.ExtendedBasicInformationTrait
let response = try await extendedBasicInformationTrait.getSerialNumber()
let serialNumber = response.serialNumber
```

## Get the most recent time of device cloud contact

To find the most recent time that the device had contact with the cloud, use
the `lastContactTimestamp` attribute of the
[`ExtendedGeneralDiagnostics`](https://developers.home.google.com/reference/kotlin/com/google/home/google/ExtendedGeneralDiagnostics)
trait:

```swift
if let lastContactTimeStamp = extendedGeneralDiagnosticsTrait.attributes.lastContactTimestamp {
  self.lastContactTime = Date(timeIntervalSince1970: Double(lastConnectedTimeStamp))
}
```

## Camera mount type settings

The [`Mount`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/MountTrait) trait
contains camera mount settings and status information. You can read
attributes such as the mount state, detection type, and mount type name.
In addition, you can use the `Mount` trait to override the default
mount type configuration.

```swift
// 1. Get the Mount trait
guard let mountTrait = deviceType.traits[Google.MountTrait.self] else {
  print("Mount trait not supported or configured on this device.")
  return
}

// 2. Read the current mount state, detection type, and type name
let mountState         = mountTrait.attributes.mountState         // Type: Google.MountTrait.MountStateEnum?
let mountDetectionType = mountTrait.attributes.mountDetectionType // Type: Google.MountTrait.MountDetectionTypeEnum?
let mountTypeName      = mountTrait.attributes.mountTypeName      // Type: String?

// 3. Update the mount type override
try await mountTrait.update { mutableTrait in
  mutableTrait.setMountTypeOverride(.official)
}
```

## 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.

```swift
let cameraConnectivity = cameraDeviceType.metadata.sourceConnectivity.connectivityState
```

A state of `partiallyOnline` 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.

> [!IMPORTANT]
> **Important:** A device that has a `connectivityState` of [`partiallyOnline`](https://developers.home.google.com/reference/swift/GoogleHomeSDK/Enums/ConnectivityState#partiallyonline) should be represented to the user as "Online."

### Get the IP address of the device

To find the IP address of the device, use the `networkInterfaces` attribute of
the
[`GeneralDiagnosticsTrait`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/GeneralDiagnosticsTrait).
The addresses are returned as `Data` objects, which you can format to
standard IPv4 or IPv6 strings using the `Network` framework:

    func getIpAddresses(trait: Matter.GeneralDiagnosticsTrait) -> [String] {
      let interfaces = trait.attributes.networkInterfaces ?? []
      var ipAddresses: [String] = []

      for interface in interfaces {
        for data in interface.iPv4Addresses {
          if let ipv4 = IPv4Address(data) {
            ipAddresses.append(String(describing: ipv4))
          }
        }
        for data in interface.iPv6Addresses {
          if let ipv6 = IPv6Address(data) {
            ipAddresses.append(String(describing: ipv6))
          }
        }
      }

      return ipAddresses
    }

## Start a livestream

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

To start a livestream, send the Session Description Protocol (SDP) string
to the
[`WebRtcLiveViewTrait`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/WebRtcLiveViewTrait)
trait's
[`startLiveView(offerSdp:)`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/WebRtcLiveViewTrait#startliveviewoffersdp:)
method, which returns 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.

    public func sendOffer(offerSdp: String) async throws
    -> (answerSdp: String, mediaSessionId: String, liveViewDuration: TimeInterval)
    {
      do {
        // Sending StartLiveView command
        let response = try await liveViewTrait.startLiveView(
          offerSdp: offerSdp
        )
        // Received StartLiveView response
        return (
          answerSdp: response.answerSdp,
          mediaSessionId: response.mediaSessionId,
          liveViewDuration: TimeInterval(response.liveSessionDurationSeconds)
        )
      } catch {
        // Failed to send StartLiveView command
        throw error
      }
    }

### Extend a livestream

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

Livestreams have a preset duration after which they expire. To lengthen the
duration of an active stream, issue an extension request using the
[`extendLiveView(mediaSessionId:optionalArgsProvider:)`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/WebRtcLiveViewTrait#extendliveviewmediasessionid:optionalargsprovider:)
method:

    public func extendLiveView(mediaSessionId: String) async throws {
      do {
        // Extending live view
        let extendedDuration = try await liveViewTrait.extendLiveView(mediaSessionId: mediaSessionId)
      } catch {
        // Failed to extend live view
        throw error
      }
    }

### Start and stop talkback

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

To start talkback, call the
[`WebRtcLiveViewTrait`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/WebRtcLiveViewTrait)
trait's [`startTalkback(mediaSessionId:optionalArgsProvider:)`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/WebRtcLiveViewTrait#starttalkbackmediasessionid:optionalargsprovider:) method.
To stop, use [`stopTalkback(mediaSessionId:)`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/WebRtcLiveViewTrait#stoptalkbackmediasessionid:).

    public func toggleTwoWayTalk(isOn: Bool, mediaSessionId: String) async throws {
      do {
        if isOn {
          try await liveViewTrait.startTalkback(mediaSessionId: mediaSessionId)
        } else {
          try await liveViewTrait.stopTalkback(mediaSessionId: mediaSessionId)
        }
      } catch {
        throw HomeError.commandFailed("Failed to toggle twoWayTalk: \(error)")
      }
    }

### Manage livestream

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

Adjusting the livestream quality is useful to optimize bandwidth usage based on
the client's viewing context (for example, switching to a lower resolution
when displaying a smaller preview tile, grid view, or picture-in-picture mode).

Changing the quality dynamically by using the
[`WebRtcLiveView`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/WebRtcLiveViewTrait)
trait specifically manages the resolution of the active livestream session
on a particular client. It is not the same as configuring a device-wide
bandwidth usage setting directly on the device, which would affect all
concurrent viewers and the quality of historical video recordings
saved to the cloud.

The following example demonstrates how to retrieve and update the livestream
quality for a device:

- Retrieve supported quality options: Get the available streaming resolutions
  supported by the device. The code queries the `WebRtcLiveView`
  trait to expose the supported stream qualities as a list of `QualityHint`
  values (such as `.sd`, `.hd`, `.fhd`, `.qhd`, or `.uhd`) by using the
  `supportedQualityHints` property.

- Change the livestream quality: Apply a selected `QualityHint` to change
  the streaming resolution of the active livestream
  (for example, switching from Standard Definition to High Definition).
  The `updateQualityHint` function uses the `WebRtcLiveView` trait's
  `changeLiveViewQuality` method to apply the selected `QualityHint`
  configuration to the active media session.

```swift
public var supportedQualityHints: [Google.WebRtcLiveViewTrait.QualityHint] {
  return liveViewTrait?.attributes.supportedQualityHints ?? []
}

public func updateQualityHint(
  liveViewTrait: Google.WebRtcLiveViewTrait,
  hint: Google.WebRtcLiveViewTrait.QualityHint,
  mediaSessionId: String
) async {
  do {
    _ = try await liveViewTrait.changeLiveViewQuality(
      mediaSessionId: mediaSessionId,
      qualityHint: hint
    )
  } catch {
    // error
  }
}
```

## Enable and disable recording capability

To enable the camera's recording capability, pass
[`TransportStatusEnum.Active`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait/TransportStatusEnum#active)
to the
[`PushAvStreamTransportTrait`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait)
trait's
[`setTransportStatus(transportStatus:optionalArgsProvider:)`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait#settransportstatustransportstatus:optionalargsprovider:)
method. To disable the recording capability, pass it
[`TransportStatusEnum.Inactive`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait/TransportStatusEnum#inactive).
In the following example, we wrap these calls in a single call that uses a
`Boolean` to toggle the recording capability:

    public func toggleIsRecording(isOn: Bool) {
      self.uiState = .loading

      guard let pushAvStreamTransportTrait else {
        // PushAvStreamTransportTrait not found.
        return
      }
      Task {
        do {
          try await pushAvStreamTransportTrait.setTransportStatus(
            transportStatus: isOn ? .active : .inactive)
          if isOn {
            do {
              self.player = try self.createWebRtcPlayer()
            } catch {
              // Failed to initialize WebRtcPlayer
              self.uiState = .disconnected
              return
            }
            await self.player?.initialize()
            self.uiState = .live
          } else {
            self.player = nil
            self.uiState = .off
          }
        } catch {
          // Failed to toggle onOff
        }
      }
    }

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 [`connectivityState` of the
  device type](https://developers.home.google.com/apis/ios/device#check_connectivity_for_a_device).
- The livestream cannot be accessed, nor does the camera detect any cloud events.

### Check to see 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:

    public func isDeviceRecording() -> Bool {
      guard let pushAvStreamTransportTrait else {
        // PushAvStreamTransportTrait not found.
        return false
      }
      guard
        let hasActiveConnection =
          pushAvStreamTransportTrait
          .attributes
          .currentConnections?
          .contains(where: { $0.transportStatus == .active })
      else {
        return false
      }
      return hasActiveConnection
    }

## Retrieve camera snapshots

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

Use the `CameraSnapshot` trait to retrieve static image snapshots from a camera.
These snapshots are useful for several scenarios:

- As a placeholder tile in the UI while a [WebRTC
  livestream](https://developers.home.google.com/apis/ios/device/camera#start_a_livestream) is loading.
- As a static preview image that upgrades to a livestream upon user interaction.
- As a background canvas for drawing and configuring custom [activity
  zones](https://developers.home.google.com/apis/ios/device/camera#activity-zones).

The `CameraSnapshot` trait offers two ways to fetch snapshots, depending on
whether you need a cached snapshot for fast rendering or an on-demand live
snapshot.

### Get a cached preview snapshot

A preview snapshot is a cached image that the SDK can retrieve without waking
the camera. This is the fastest method to fetch a static image and is ideal
for camera overview pages or dashboard grids.

To get the preview snapshot, read the `preview_image_url` trait attribute:

```swift
guard let cameraSnapshotTrait = deviceType.traits[
  Google.CameraSnapshotTrait.self
] else {
  print("CameraSnapshot trait not supported on this device.")
  return
}

if let previewImageUrlString = cameraSnapshotTrait
  .attributes.preview_image_url,
   let url = URL(string: previewImageUrlString) {
  // Load the preview image from the URL
}
```

Depending on camera configuration and activity, the preview URL points to a
cached image generated from recent video footage (the first I-frame of the
latest video fragment) or a snapshot periodically uploaded by the camera.

To indicate the freshness of the image, the Google Home cloud embeds an
`X-Home-Image-Captured-At` header in the served
JPEG/PNG image, formatted in UTC. You can parse this header on the
client-side to display the age of the snapshot in an app.

### Get an on-demand live snapshot

For user journeys that require the camera's current live view---such as setting
up Activity Zones---you can request a live snapshot. Triggering a live snapshot
instructs the camera to wake up, capture a new frame, and upload it to the
cloud.

To request a live snapshot, use the `getLiveSnapshot()` command:

```swift
do {
  let response = try await cameraSnapshotTrait.getLiveSnapshot()
  let snapshotUrlString = response.snapshot_url

  if let url = URL(string: snapshotUrlString) {
    // Load the live snapshot image from the URL
  }
} catch {
  print("Failed to get live snapshot: \(error)")
}
```

> [!WARNING]
> **Warning:** Requesting a live snapshot is relatively slow and resource-intensive because it wakes up battery-powered or sleeping cameras. Only use this command when a fresh, real-time image is required. For general UI previews, use the cached `preview_image_url` instead.

### Authenticate snapshot requests

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

All snapshot URLs point to secure media and require an OAuth 2.0 token for the
Home APIs v2 scope. To download and render the images, the OAuth token must be
injected as a Bearer token in the `Authorization` header of your HTTP request.

The following example demonstrates how to configure a secure network request
to download a snapshot:

```swift
import UIKit

func loadSnapshotImage(from url: URL, home: Home) async -> UIImage? {
  do {
    // 1. Retrieve the OAuth access token from the Home APIs SDK
    let (accessToken, _) = try await home.permissions.authorization()

    // 2. Configure the HTTP GET request with the Bearer token
    var request = URLRequest(url: url)
    request.setValue(
      "Bearer \(accessToken)",
      forHTTPHeaderField: "Authorization"
    )

    // 3. Fetch the image data
    let (data, _) = try await URLSession.shared.data(for: request)
    return UIImage(data: data)
  } catch {
    print("Error loading snapshot image: \(error)")
    return nil
  }
}
```

## 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`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/EnergyPreferenceTrait/Attributes#currentenergybalance) attribute
of the [`EnergyPreference`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/EnergyPreferenceTrait)
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.

```json
// Example energyBalances list
{
  "energy_balances": [
    {
      "step": 0,
      "label": "EXTENDED"
    },
    {
      "step": 50,
      "label": "BALANCED"
    },
    {
      "step": 100,
      "label": "PERFORMANCE"
    }
  ]
}
```

```swift
private func setBatteryUsage(to option: UInt8) async throws {
  _ = try await energyPreferenceTrait.update {
    $0.setCurrentEnergyBalance(option)
  }
}
```

### Turn on automatic battery saver

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

To configure this feature, update the
[`currentLowPowerModeSensitivity`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/EnergyPreferenceTrait/Attributes#currentlowpowermodesensitivity) attribute
of the [`EnergyPreference`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/EnergyPreferenceTrait)
trait. This attribute uses an index
to select a sensitivity level, where `0` typically represents `Disabled`
and `1` represents `Enabled` or `Automatic`.

```swift
private func setAutoBatterySaver(to value: Bool) async throws {
  _ = try await energyPreferenceTrait.update {
    $0.setCurrentLowPowerModeSensitivity(value ? 1 : 0)
  }
}
```

### Get the battery charging state

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

To get the device's current charging state (charging, fully charged, or not
charging), use the
[`batChargeState`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/PowerSourceTrait/Attributes#batchargestate)
attribute of the
[`PowerSource`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/PowerSourceTrait)
trait.

```swift
self.chargingState = powerSourceTrait.attributes.batChargeState

var description: String
switch self.chargingState {
case .isCharging:
  description = "Charging"
case .isAtFullCharge:
  description = "Full"
case .isNotCharging:
  description = "Not Charging"
default:
  description = "Unknown"
}
```

### Get the battery level

To get the current battery level, use the
[`batChargeLevel`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/PowerSourceTrait/Attributes#batchargelevel)
attribute of the
[`PowerSource`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/PowerSourceTrait)
trait. The level is either `OK`, `Warning` (low), or `Critical`.

```swift
self.batteryLevel = powerSourceTrait.attributes.batChargeLevel

var description: String
switch self.batteryLevel {
case .ok:
  description = "OK"
case .warning:
  description = "Warning"
case .critical:
  description = "Critical"
default:
  description = "Unknown"
}
```

### Get the power source

To determine the power source the device is using,
use the [`BatPresent`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/PowerSourceTrait/Attributes#batpresent)
and
[`wiredPresent`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/PowerSourceTrait/Attributes#wiredpresent)
attributes of the
[`PowerSource`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/PowerSourceTrait)
trait.

```swift
if powerSourceTrait.attributes.wiredPresent ?? false {
  self.powerSourceType = .wired
} else if powerSourceTrait.attributes.batPresent ?? false {
  self.powerSourceType = .battery
} else {
  self.powerSourceType = nil
}
```

### Check to see if the battery needs to be replaced

The [`batReplaceability`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/PowerSourceTrait/Attributes#batreplaceability)
attribute indicates whether the battery is unreplaceable, user-replaceable, or
factory-replaceable.

If the battery is replaceable, the
[`batReplacementNeeded`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/PowerSourceTrait/Attributes#batreplacementneeded)
attribute of the
[`PowerSource`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/PowerSourceTrait)
trait tells you whether the battery needs to be replaced.

```swift
// Get the battery replacement status
var batteryStatus = powerSourceTrait.attributes.batReplacementNeeded

if batteryStatus {
  print("Replace the battery.")
}
```

When the battery is user-replaceable, the
[`batReplacementDescription`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Matter/PowerSourceTrait/Attributes#batreplacementdescription)
describes the battery, including information such as form factor, chemistry, and
preferred manufacturer.

## 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`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/CameraAvStreamManagementTrait/Attributes#microphonemuted)
attribute of the `CameraAvStreamManagementTrait` trait using the built-in
`setMicrophoneMuted` function:

    // Turn the device's microphone on or off
    func setMicrophone(on: Bool) async {
      do {
        _ = try await self.cameraAvStreamManagementTrait?.update {
          $0.setMicrophoneMuted(!on)
        }
      } catch {
        // Error
      }
    }

### Turn audio recording on or off

To turn audio recording on or off for the device, update the
[`recordingMicrophoneMuted`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/CameraAvStreamManagementTrait/Attributes#recordingmicrophonemuted)
attribute of the `CameraAvStreamManagementTrait` trait using the built-in
`setRecordingMicrophoneMuted` function:

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

### Adjust the speaker volume

To adjust the speaker volume for the device, update the
[`speakerVolumeLevel`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/CameraAvStreamManagementTrait/Attributes#speakervolumelevel)
attribute of the `CameraAvStreamManagementTrait` trait using the built-in
`setSpeakerVolumeLevel` function:

    // Adjust the camera speaker volume
    func setSpeakerVolume(to value: UInt8) async {
      do {
        _ = try await cameraAvStreamManagementTrait.update {
          $0.setSpeakerVolumeLevel(value)
        }
      } catch {
        // Error
      }
    }

## Activity zone settings

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

The `ZoneManagement` trait provides an interface for managing custom
regions of interest (activity zones) on camera and doorbell devices.
These zones are used to filter event detection (such as person
or vehicle motion) to specific areas within the device's field of view.

Activity zones are configured by the user within a partner application,
allowing them to draw zones over specific areas in the camera's field of view.
These user-defined zones are then translated into the structures used by this trait.
For more information on how activity zones work, see
[Set up and use Activity Zones](https://support.google.com/googlenest/answer/9207697).

Activity zones are typically defined using 2D Cartesian coordinates.
The trait provides the
[`TwoDCartesianVertexStruct`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/ZoneManagementTrait/TwoDCartesianVertexStruct) for vertices and the
[`TwoDCartesianZoneStruct`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/ZoneManagementTrait/TwoDCartesianZoneStruct)
for the zone definition (name, vertices, color, and usage).

### Check activity zones

To display activity zones, check the
[`zones`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/ZoneManagementTrait/Attributes#zones)
attribute of the `ZoneManagement` trait.

```swift
let zoneManagementTrait: Google.ZoneManagementTrait

self.zones = zoneManagementTrait.attributes.zones ?? []
```

### Add an activity zone

To create a new zone, use the
[`createTwoDCartesianZone`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/ZoneManagementTrait#createtwodcartesianzonezone:) command. This command takes a [`TwoDCartesianZoneStruct`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/ZoneManagementTrait/TwoDCartesianZoneStruct),
which defines the zone's name, vertices, color, and usage.

The following example shows how to create a zone named "Front Porch" with four
vertices, colored salmon (#F439A0), and used for motion detection.

```swift
import GoogleHomeSDK
import GoogleHomeTypes

func createFrontPorchZone(trait: Google.ZoneManagementTrait) async {
  // 1. Define the vertices for the zone (2D Cartesian coordinates)
  // Values are UInt16, typically scaled to the device's twoDCartesianMax.
  let vertices = [
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 260, y = 422),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1049, y = 0),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048, y = 0),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048, y = 950),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1630, y = 1349),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 880, y = 2048),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 0, y = 2048),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 638, y = 1090)
  ]

  // 2. Define the zone structure using the given SDK struct
  let newZone = Google.ZoneManagementTrait.TwoDCartesianZoneStruct(
    name: "Front Porch",
    use: [.motion], // ZoneUseEnum.motion
    vertices: vertices,
    // Color is a hex string (for example, Salmon/Pink)
    color: "#F439A0"
  )

  do {
    // 3. Execute the raw command to add the zone to the device
    // This returns the created zone's ID (UInt16).
    var newZoneID = try await trait.createTwoDCartesianZone(zone: newZone)
  } catch {
    // Error
  }
}
```

### Update an activity zone

To update an existing zone, use the
[`updateTwoDCartesianZone`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/ZoneManagementTrait#updatetwodcartesianzonezoneid:zone:) command. This command requires the `zoneId` and the updated
[`TwoDCartesianZoneStruct`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/ZoneManagementTrait#twodcartesianzonestruct).

```swift
let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16
let zone: Google.ZoneManagementTrait.TwoDCartesianZoneStruct

do {
  _ = try await zoneManagementTrait.updateTwoDCartesianZone(
        zoneID: zoneID, zone: zone)
} catch {
  // Error
}
```

### Delete an activity zone

To remove a zone, use the
[`removeZone`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/ZoneManagementTrait#removezonezoneid:) command with the specific `zoneId`.

```swift
let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16

do {
  _ = try await zoneManagementTrait.removeZone(zoneID: zoneID)
} catch {
  // Error
}
```

## Sound Event Triggers

The `AvStreamAnalysis` trait provides an interface for managing event detection
triggers on camera and doorbell devices. While vision-based triggers
(such as people or vehicles) can be zone-specific, sound-related triggers
are typically device-level configurations.

The following trigger types are available for sound detection with the
[`EventTriggerTypeEnum`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/AvStreamAnalysisTrait/EventTriggerTypeEnum):

| Mode | Enum value | Description |
|---|---|---|
| Sound | `Sound` | General sound detection. |
| Person talking | `PersonTalking` | Detects speech. |
| Dog bark | `DogBark` | Detects canine vocalizations. |
| Glass break | `GlassBreak` | Detects the sound of breaking glass. |
| Smoke alarm | `SmokeAlarm` | Detects smoke alarms, often recognized by the T3 audible pattern (three short beeps followed by a pause). |
| CO alarm | `CoAlarm` | Detects carbon monoxide (CO) alarms, typically recognized by the T4 audible pattern (four short beeps followed by a pause). |

### Check sound detection status

To display the current state of sound detection to the user, you must check
what the device supports and what is enabled by the device hardware.
The two attributes to check are:

- [`supportedEventTriggers`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/AvStreamAnalysisTrait/Attributes#supportedeventtriggers)
- [`enabledEventTriggers`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/AvStreamAnalysisTrait/Attributes#enabledeventtriggers)

In iOS development, you typically would access the `AvStreamAnalysis` trait
from the device to read these attributes.

```swift
// Example struct to store event triggers
public struct EventTrigger: Equatable {
  public var id: Google.AvStreamAnalysisTrait.EventTriggerTypeEnum
  public var enabled: Bool
}

let avStreamAnalysisTrait: Google.AvStreamAnalysisTrait

let possibleEventTriggers = avStreamAnalysisTrait.attributes.supportedEventTriggers ?? []
let enabledEventTriggers = avStreamAnalysisTrait.attributes.enabledEventTriggers ?? []

let eventTriggers [EventTrigger] = []
for trigger in possibleEventTriggers {
  self.eventTriggers.append(
    EventTrigger(
      id: trigger,
      enabled: enabledEventTriggers.contains(trigger)
    )
  )
}
```

### Update the set of enabled triggers

To update the set of enabled triggers, use the
[`SetOrUpdateEventDetectionTriggers`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/AvStreamAnalysisTrait#setorupdateeventdetectiontriggerseventtriggerenablements:)
command, which takes a list of `EventTriggerEnablement` structures.

```swift
// Example struct to store event triggers
public struct EventTrigger: Equatable {
  public var id: Google.AvStreamAnalysisTrait.EventTriggerTypeEnum
  public var enabled: Bool
}

let avStreamAnalysisTrait: Google.AvStreamAnalysisTrait
let eventTriggers: [EventTrigger]

let enabledEventTriggers = eventTriggers.map {
  Google.AvStreamAnalysisTrait.EventTriggerEnablement(
    eventTriggerType: $0.id,
    enablementStatus: $0.enabled ? .enabled : .disabled
  )
}

try await avStreamAnalysisTrait.setOrUpdateEventDetectionTriggers(
  eventTriggerEnablements: enabledEventTriggers
)
```

## Recording modes

[Implemented in Sample App for iOS](https://developers.home.google.com/apis/ios/sample-app/build)

The `RecordingMode` trait provides an interface for managing the video
and image recording behavior on camera and doorbell devices. It allows
users to choose between continuous recording, event-based recording,
or disabling recording entirely (Live View only).

The [`RecordingModeEnum`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/RecordingModeTrait/RecordingModeEnum)
defines the available recording strategies:

| Mode | Enum value | Description |
|---|---|---|
| **Disabled** | `Disabled` | Recording is completely disabled. Used mainly by legacy devices. |
| **CVR** (Continuous Video Recording) | `Cvr` | Video is recorded 24x7. Requires a subscription (for example, Google Home Premium. |
| **EBR** (Event Based Recording) | `Ebr` | Recording is triggered by events (person, motion). Video length depends on the event duration and subscription. |
| **ETR** (Event Triggered Recording) | `Etr` | Short preview recording (for example, 10 seconds) triggered by events. |
| **Live View** | `LiveView` | Recording is disabled, but users can still access the livestream. |
| **Still Images** | `Images` | Snapshots are recorded instead of video when events occur. |

### Check recording modes

To display the current recording configuration, check the attributes
of the `RecordingMode` trait:

- [`supportedRecordingModes`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/RecordingModeTrait/Attributes#supportedrecordingmodes) - All potential modes
- [`availableRecordingModes`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/RecordingModeTrait/Attributes#availablerecordingmodes) - Selectable modes
- [`selectedRecordingMode`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/RecordingModeTrait/Attributes#selectedrecordingmode) - The active mode

```swift
// Example struct to store recording modes.
public struct RecordingMode: Hashable {
  public let id: UInt8
  public let mode: Google.RecordingModeTrait.RecordingModeEnum
}

let recordingModeTrait: Google.RecordingModeTrait

if let availableRecordingModes = recordingModeTrait.attributes.availableRecordingModes,
   let supportedRecordingModes = recordingModeTrait.attributes.supportedRecordingModes,
   let selectedRecordingMode = recordingModeTrait.attributes.selectedRecordingMode {

  var recordingModes: [RecordingMode] = []

  for recordingModeId in availableRecordingModes {
    guard Int(recordingModeId) < supportedRecordingModes.count,
          Int(recordingModeId) >= 0 else {
      // Out of bounds error
    }

    recordingModes.append(
      RecordingMode(
        id: recordingModeId,
        mode: supportedRecordingModes[Int(recordingModeId)].recordingMode,
      )
    )
  }
}
```

### Change the recording mode

Before updating, ensure that the chosen index from the `supportedRecordingModes`
attribute is present in the `availableRecordingModes` attribute.

> [!WARNING]
> **Warning:** If a user changes the recording mode from `EBR` or `CVR` to either `Disabled` or `Live View`, their video history is deleted. Your app should warn users before they make this change.

To update the selected mode, use the
`setSelectedRecordingMode` function, passing the index of the chosen mode:

```swift
let recordingModeTrait: Google.RecordingModeTrait
let recordingModeID: UInt8

_ = try await recordingModeTrait.update {
  $0.setSelectedRecordingMode(recordingModeID)
}
```

## Other settings

Various other settings can be controlled through the Home APIs.

### Change the image orientation

The orientation of the camera image (video) can be rotated. The video can only
be rotated 180 degrees.

> [!NOTE]
> **Note:** This is not supported for doorbells.

To change the camera's image orientation, update the
[`imageRotation`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/CameraAvStreamManagementTrait/Attributes#imagerotation)
attribute of the `CameraAvStreamManagementTrait` trait using the built-in
`setImageRotation` function:

    // Change the camera's image orientation
    // Value must be 0 or 180
    func setImageRotation(to value: UInt16) async {
      do {
        _ = try await cameraAvStreamManagementTrait.update {
          $0.setImageRotation(value)
        }
      } catch {
        // Error
      }
    }

### Turn night vision on or off

To turn night vision on or off for the camera, use [`TriStateAutoEnum`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/CameraAvStreamManagementTrait/TriStateAutoEnum)
to update the
[`nightVision`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/CameraAvStreamManagementTrait/Attributes#nightvision)
attribute of the `CameraAvStreamManagementTrait` trait using the built-in
`setNightVision` function:

    // Turn night vision on or off
    func setNightVision(
      to value: Google.CameraAvStreamManagementTrait.TriStateAutoEnum
    ) async {
      do {
        _ = try await cameraAvStreamManagementTrait.update {
          $0.setNightVision(value)
        }
      } catch {
        // Error
      }
    }

### Change the brightness of the status LED

To change the brightness of the status LED, use
[`ThreeLevelAutoEnum`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/CameraAvStreamManagementTrait/ThreeLevelAutoEnum)
to update the
[`statusLightBrightness`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/CameraAvStreamManagementTrait/Attributes#statuslightbrightness)
attribute of the `CameraAvStreamManagementTrait` trait using the built-in
`setStatusLightBrightness` function:

    // Set the LED brightness
    func setStatusLightBrightness(
      to value: Google.CameraAvStreamManagementTrait.ThreeLevelAutoEnum
    ) async {
      do {
        _ = try await cameraAvStreamManagementTrait.update {
          $0.setStatusLightBrightness(value)
        }
      } catch {
        // Error
      }
    }

### 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](https://support.google.com/googlenest/answer/9251364)
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`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/CameraAvStreamManagementTrait/Attributes#viewport)
attribute of the `CameraAvStreamManagementTrait` trait with a `ViewportStruct`, using
the built-in `setViewport` function.

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

    }

### Generate a TransportOptionsStruct

Some settings require modifications to properties in a `TransportOptionsStruct`,
which is then passed into the transport options of a streaming connection. For
Swift, this struct needs to be generated prior to updating any properties.

Use this helper function to generate the struct for use with the following
setting changes:

- [Adjust the device wake-up sensitivity](https://developers.home.google.com/apis/ios/device/camera#wake-up-sensitivity)
- [Adjust the maximum event length](https://developers.home.google.com/apis/ios/device/camera#max-event-length)

    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
    }

### Enable or disable analytics

Each device may individually opt-in to send detailed analytics data to the
Google Home cloud (see [Cloud Monitoring for Home
APIs](https://developers.home.google.com/apis/ios/eap/analytics/monitoring)).

> [!IMPORTANT]
> **Important:** Before enabling analytics for a device, the partner should prompt the user to confirm whether or not the user agrees to permit sharing analytics data for that device. Partners should also provide a clear and straightforward way to opt out of sending analytics data for each device.

To enable analytics for a device, set the
[`analyticsEnabled`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/ExtendedGeneralDiagnosticsTrait/Attributes#analyticsEnabled))
property of the
[`ExtendedGeneralDiagnosticsTrait`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/ExtendedGeneralDiagnosticsTrait)
to `true`. When you set `analyticsEnabled`,
another property, `logUploadEnabled`, is automatically set to `true`, which
allows the analytics log files to be uploaded to the Google Home cloud.

    // Enable analytics
    _ = try await extendedGeneralDiagnosticsTrait.update {
      $0.setAnalyticsEnabled(true)
    }

    // Disable analytics
    _ = try await extendedGeneralDiagnosticsTrait.update {
      $0.setAnalyticsEnabled(false)
    }

## Transport and recording configurations

This section covers settings related to camera streaming quality and
event triggering. These settings are managed by the
[`PushAvStreamTransport`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait)
trait.

### Read transport settings

This section demonstrates how to retrieve the current configuration from
a camera or doorbell device. It fetches the `PushAvStreamTransport` trait,
finds the specific connection used for recording, and then extracts
the current values for bandwidth quality, wake-up sensitivity,
and maximum event length.

```swift
// Assuming access to
// var pushAvStreamTransportTrait: Google.PushAvStreamTransportTrait
let connections = try await pushAvStreamTransportTrait.findTransport().transportConfigurations

// Locate the connection designated for recording
let recordingConnection = connections.first { connection in
    guard let transportOptions = connection.transportOptions else { return false }
    return transportOptions.streamUsage == .recording
}

let options = recordingConnection?.transportOptions

// 1. Bandwidth Quality (Video Stream ID)
let videoStreamId = options?.videoStreamID

// 2. Wake-up Sensitivity (Motion Sensitivity)
let wakeUpSensitivity = options?.triggerOptions.motionSensitivity

// 3. Max Event Length (Motion Trigger Time Control)
let maxEventLength = options?.triggerOptions.motionTimeControl?.maxDuration
```

### Update transport settings

This section shows how to change the transport settings.
It creates a new `TransportOptionsStruct` containing the new values and
then uses the `modifyPushTransport` command to send these updated settings
back to the device, applying them to the recording connection found
in the previous step.

To modify these settings, use the
[`modifyPushTransport` command](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait?db=rhodie#modifypushtransportconnectionid:transportoptions:)
with a [`TransportOptionsStruct`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait/TransportOptionsStruct).

```swift
// Example: Updating to Max Quality and 30s duration
let currentOptions = recordingConnection!.transportOptions!
let newOptions = Google.PushAvStreamTransportTrait.TransportOptionsStruct(
    streamUsage: .recording,
    videoStreamID: 2, // Max Quality
    tlsEndpointID: currentOptions.tlsEndpointID,
    url: currentOptions.url,
    triggerOptions: Google.PushAvStreamTransportTrait.TransportTriggerOptionsStruct(
        triggerType: .motion,
        motionSensitivity: 5, // Medium
        motionTimeControl: Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct(
            initialDuration: currentOptions.triggerOptions.motionTimeControl?.initialDuration ?? 10,
            augmentationDuration: currentOptions.triggerOptions.motionTimeControl?.augmentationDuration ?? 5,
            maxDuration: 30,
            blindDuration: currentOptions.triggerOptions.motionTimeControl?.blindDuration ?? 0
        )
    ),
    ingestMethod: currentOptions.ingestMethod,
    containerOptions: currentOptions.containerOptions
)

try await pushAvStreamTransportTrait.modifyPushTransport(
    connectionID: recordingConnection!.connectionID,
    transportOptions: newOptions
)
```

### Determine bandwidth quality

The [`videoStreamId`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait/TransportOptionsStruct#videostreamid)
property of the [`TransportOptionsStruct`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait/TransportOptionsStruct) corresponds to a
specific video stream configuration.

To get the supported video streams, refer to the
`allocatedVideoStreams` attribute,
which is a list of [`VideoStreamStructs`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/CameraAvStreamManagementTrait#videostreamtruct).
from the `CameraAvStreamManagement` trait for the device.

### Adjust the device wake-up sensitivity

The [`motionSensitivity`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait/TransportTriggerOptionsStruct#motionsensitivity)
property of the [`TransportTriggerOptionsStruct`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait/TransportTriggerOptionsStruct) corresponds to the
following values:

| Label | Value (UInt8) |
|---|---|
| Low | 1 |
| Medium | 5 |
| High | 10 |

### Adjust the maximum event length

The [`maxDuration`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait/TransportMotionTriggerTimeControlStruct#maxduration)
property of the [`TransportMotionTriggerTimeControlStruct`](https://developers.home.google.com/reference/swift/GoogleHomeTypes/Enums/Google/PushAvStreamTransportTrait/TransportMotionTriggerTimeControlStruct)
corresponds to the following `UInt32` durations (in seconds):

- **10** , **15** , **30** , **60** , **120** , **180**

## Decommission a device

To remove a camera from a structure, call
`device.decommission()`. Decommissioning prompts the user with a
Google-managed confirmation screen warning that all recorded 24/7 video
history, event history, clips, and familiar face library data will be
permanently deleted across the structure.

For detailed instructions and code examples, see
[Remove a device](https://developers.home.google.com/apis/ios/device/remove#cameras-doorbells).