Device APIs may be accessed through the Home APIs for Android.
Import these packages into your app:

```kotlin
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id
```

To use specific device types or traits with the Device APIs, they must be
imported individually.

For example, to use the Matter On/Off trait and On/Off
Plug-in Unit device type, import the following packages into your application:

```kotlin
import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffPluginUnitDevice
```

> [!NOTE]
> **Note:** Android Studio's auto-complete feature should automatically list all available trait and device type packages when adding `import` lines to your files.

For more information, see [Data model on Android](https://developers.home.google.com/apis/android/data-model.md.txt).

## Error handling

<br />

Any method in the Home APIs can throw a
[`HomeException`](https://developers.home.google.com/reference/kotlin/com/google/home/HomeException.md.txt), so we recommend that you use a `try-catch` block to
catch `HomeException` on all calls.

When handling `HomeException`, check its
[`error.code`](https://developers.home.google.com/reference/kotlin/com/google/home/HomeError.md.txt#code()) and [`error.message`](https://developers.home.google.com/reference/kotlin/com/google/home/HomeError.md.txt#message()) fields to learn what went wrong. There may be sub-error codes
as well, so call the [`getSubErrorCodes()`](https://developers.home.google.com/reference/kotlin/com/google/home/HomeException.md.txt#getSubErrorCodes()) method and check the result.

Any unhandled exceptions will result in your app crashing.

For more information, see
[Error handling](https://developers.home.google.com/apis/android/error-handling.md.txt).

<br />

See [Send a command to a device](https://developers.home.google.com/apis/android/device/control.md.txt#send-command) for
an example.

## Sample calls

<br />

> [!CAUTION]
> **Caution:** Code examples shown here may be implemented differently than those of any sample apps, in order to illustrate basic API calls.

<br />

### Get a list of devices

Once you have a reference to the `Structure` instance, a `devices()` call
returns a `Flow` of devices accessible to you from that structure:

```kotlin
// Get a flow of all devices accessible to the user
val allDevicesFlow: HomeObjectsFlow<HomeDevice> = home.devices()

// Calling list() on a HomeObjectsFlow returns the first Set of elements.
val allDevices: Set<HomeDevice> = allDevicesFlow.list()
```

From there, you can access states for each device and send commands to devices.

With release 1.8 of the Home APIs, you have the option to have the API represent
each multipart device as a single device by setting the `devices()` method's
`enableMultipartDevices` parameter to `true`. See
[Multipart devices on Android](https://developers.home.google.com/apis/android/device/multipart.md.txt) for more
information.

### Read a device state

Look at an example of checking the `OnOff` attribute from the device's
On/Off trait. Using the Home APIs trait data model, where this trait is
identified as `OnOff`, you can retrieve trait data through the device type's
`standardTraits` class:

```kotlin
// Assuming we have a device.
val deviceFlow = home.devices().itemFlow(myDeviceId)

val device = deviceFlow.first()

// Get a flow of a standard trait on the type. distinctUntilChanged() is needed to only trigger
// on the specific trait changes and not the whole type.
val onOffTraitFlow: Flow<OnOff?> =
  device.type(DimmableLightDevice).map { it.standardTraits.onOff }.distinctUntilChanged()

val onOffTrait: OnOff = onOffTraitFlow.first()!!
```

See
[`distinctUntilChanged`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/distinct-until-changed.html)
to learn more about the Kotlin flow function.

### Invalidate state in a trait subscription

The [`TraitStateInvalidation` interface](https://developers.home.google.com/reference/kotlin/com/google/home/TraitStateInvalidation.md.txt)
provides the ability to invalidate a state retrieved through subscriptions
to the target device in cases where the state is not being reported correctly.
Examples of when the state may not be reported correctly include
using attributes in Matter traits with the "C" quality
or due to a device implementation that unexpectedly causes the issue.

This API issues a forced read of the current trait state and returns the result
through existing trait flows.

Get the trait, then run a `forceRead` on the trait:

```kotlin
val onOffTrait = device.?type(DimmableLightDevice)?.map{it.trait(OnOff)}.first()
onOffTrait.forceRead()
```

> [!IMPORTANT]
> **Important:** This API should be used sparingly because it can impact the performance and battery life of the target device.

### Get a list of device type traits

Device types should be used as an entry point for reading traits, as they
decompose a device into its functional pieces (like endpoints in
Matter).

They also account for trait collisions in the event that a device features two
device types, both of which might have the same trait. For example, if a device
is both a Speaker and Dimmable Light, it would have two On/Off and two
Level Control traits.

To get the list of available traits for the Dimmable Light device type:

```kotlin
// Get all types available on this device. Requires the types to be part of the registry during
// SDK initialization.
val typesFlow: Flow<Set<DeviceType>> = device.types()

// Get a snapshot of all types.
val types: Set<DeviceType> = typesFlow.first()

// Get the DimmableLightDevice instance from the set of types.
val dimmableLightDevice = types.filterIsInstance<DimmableLightDevice>().firstOrNull()

// Get all traits in the type + traits registered
val allTraits: Set<Trait> = dimmableLightDevice!!.traits()
```

Another kind of trait collision can occur when a device has two traits with the
same name. For example, `onOff` could refer to an instance of the standard
`OnOff` trait, or it could refer to an instance of a manufacturer-defined
`OnOff` trait. To eliminate any potential ambiguity as to which trait is
intended, a `Trait` instance referenced through a device should be preceded by a
qualifying namespace. For standard traits, that is, those that are analogous to
Matter standard clusters, use `standardTraits`. For Google
traits, use `googleTraits`:

```kotlin
// Accessing standard traits on the type.
val onOffTrait: OnOff? = dimmableLightDevice.standardTraits.onOff
val levelControlTrait: LevelControl? = dimmableLightDevice.standardTraits.levelControl
```

To access a manufacturer-specific trait, reference it directly:

```kotlin
// Accessing a custom trait on the type.
val customTrait = dimmableLightDevice.trait(MyCustomTrait)
```

### Get a list of devices with a specific trait

The
[`filter`](https://kotlinlang.org/docs/collection-filtering.html)
function in Kotlin can be used to further refine API calls. For
example, to get a list of devices in the home that all have the On/Off trait:

```kotlin
// Get all devices that support OnOff
val onOffDevices: Flow<List<HomeDevice>> =
  home.devices().map { devices -> devices.filter { it.has(OnOff) } }
```

See the [`Trait` interface](https://developers.home.google.com/reference/kotlin/com/google/home/Trait.md.txt) for a full
list of traits available in the Home APIs.

### Get a list of devices with similar device types

To get a list of devices that represent all the lights in a home:

```kotlin
// Get a list of devices with similar device types (lights)
val lightDevices =
  home.devices().map { devices ->
    devices.filter {
      it.has(DimmableLightDevice) ||
        it.has(OnOffLightDevice) ||
        it.has(ColorTemperatureLightDevice) ||
        it.has(ExtendedColorLightDevice)
    }
  }
```

There are multiple device types in the Home APIs that could represent a core
device type. For example, there is no "Light" device type. Instead, there are
four different device types that could represent a light, as shown in the
preceding example. As such, to get a comprehensive view of higher-level type of
device in a home, multiple device types must be included in filtered flows.

See the [`DeviceType` interface](https://developers.home.google.com/reference/kotlin/com/google/home/DeviceType.md.txt)
for a full list of device types available in the Home APIs.

### Get the Vendor ID or Product ID for a device

The [`BasicInformation`](https://developers.home.google.com/reference/kotlin/com/google/home/matter/standard/BasicInformation.md.txt)
trait includes information like Vendor ID, Product ID, Product Name and the
Serial Number for a device:

```kotlin
// Get device basic information. All general information traits are on the RootNodeDevice type.
val basicInformation = device.type(RootNodeDevice).first().standardTraits.basicInformation!!
println("vendorName ${basicInformation.vendorName}")
println("vendorId ${basicInformation.vendorId}")
println("productId ${basicInformation.productId}")
```

#### Cloud-to-cloud device identification for device manufacturers

If you are a device maker and build Cloud-to-cloud devices,
in order to identify your
[Cloud-to-cloud](https://developers.home.google.com/cloud-to-cloud/get-started.md.txt) devices through the
`BasicInformation` trait, you can include these string fields in
their `SYNC` response:

- The Connectivity Standards Alliance (Alliance) issued vendor ID:
  `"matterOriginalVendorId": "0xfff1",`

- A Product Identifier that uniquely identifies a product of a vendor:
  `"matterOriginalProductId": "0x1234",`

- A unique identifier for the device, which is constructed in a
  manufacturer-specific manner:
  `"matterUniqueId": "matter-device-id",`

When entering these string fields, use your Matter
Vendor and Product IDs if you have them. If you are not a
Alliance member and have not been assigned these IDs, you can
leave the `matterOriginalVendorId` and `matterOriginalProductId` fields blank
and provide the `matterUniqueId` as the identifier.

The example SYNC response shows the use of these fields:

```json
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "agentUserId": "1836.15267389",
    "devices": [
      {
        "id": "456",
        "type": "action.devices.types.LIGHT",
        "traits": [
          "action.devices.traits.OnOff",
          "action.devices.traits.Brightness",
          "action.devices.traits.ColorSetting",
        ],
        "willReportState": true,
        "deviceInfo": { ... },
        "matterOriginalVendorId": "0xfff1",
        "matterOriginalProductId": "0x1234",
        "matterUniqueId": "matter-device-id",
        "otherDeviceIds": [
          {
            "deviceId": "local-device-id",
          }
        ]
      }
    ]
  }
}
```

For more information, see
[Cloud-to-cloud `SYNC` documentation](https://developers.home.google.com/cloud-to-cloud/integration/sync.md.txt#sync-request).

## Device and trait metadata

Devices and traits in the Home APIs have metadata associated with them,
which can help in managing the user experience in an app.

Each trait in the Home APIs contains a
[`sourceConnectivity`](https://developers.home.google.com/reference/kotlin/com/google/home/SourceConnectivity.md.txt)
property, which has information about a trait's online status and locality
(local or remote routing).

### Get the primary type of a device

Some devices may present multiple device types through the Home APIs.
To ensure users are presented with the appropriate options in
an app (such as device control and suggested automations) for their devices,
it's useful to check what the primary device type for a device is.

> [!IMPORTANT]
> **Important:** A device can have more than one primary type.
>
> - All types belonging to the primary endpoint are considered primary types.
> - If one member of a Matter superset type, such as a light, is primary, all other members of that superset type that are present in the device are also primary. For example, if a device supports `OnOffLightDevice`, `DimmableLightDevice`, `ColorTemperatureLightDevice` and `ExtendedColorLightDevice`, and one of them is primary, they are all primary. For more information on superset device types, see the Matter *Application Cluster Specification* , section 9.2.5, *Superset Device Types*.

First, get the type(s) of the device using
[`type()`](https://developers.home.google.com/reference/kotlin/com/google/home/HasDeviceTypes.md.txt#type(com.google.home.DeviceTypeFactory)),
then determine the primary type(s):

```kotlin
val types = device.types().first()
val primaryTypes = types.filter { it.metadata.isPrimaryType }
```

### Check if a trait is online

Use the `connectivityState()` method to check a trait's connectivity:

```kotlin
val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState
```

Some traits, typically Google smart home traits, may show
offline if the device doesn't have internet connectivity. This is because
these traits are cloud-based and don't have local routing.

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

```kotlin
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.

> [!IMPORTANT]
> **Important:** A device that has a `connectivityState` of [`PARTIALLY_ONLINE`](https://developers.home.google.com/reference/kotlin/com/google/home/ConnectivityState.md.txt#PARTIALLY_ONLINE) 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
[`GeneralDiagnostics`](https://developers.home.google.com/reference/kotlin/com/google/home/matter/standard/GeneralDiagnostics.md.txt)
trait. The addresses are returned as byte arrays, which you can format to
standard IPv4 or IPv6 strings:

```kotlin
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()
```

### Check the network routing of a trait

The locality for a trait is also available in the Home APIs. The
`dataSourceLocality` indicates whether the trait is routed remotely (through
the cloud), locally (through a local hub), or peer-to-peer (direct from device
to device, no hub).

The unknown locality value `UNSPECIFIED` is possible, for example, while an app
is booting and hasn't yet reached a hub or server for device connectivity. These
devices aren't reachable and will fail interaction requests from commands or
events. It is up to the client to determine how to handle such devices.

```kotlin
val onOffLocality = onOffTrait?.metadata?.sourceConnectivity?.dataSourceLocality
```

### Check the network routing for a device

Like connectivity, locality is checked at a device type level. The state
returned is a combination of the locality for all traits on that device.

```kotlin
val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality
```

A state of `MIXED` may be observed in a similar scenario
as that of `PARTIALLY_ONLINE` connectivity: some traits are cloud-based while
others are local.

### Change the name of a device

Call the [`setName()`](https://developers.home.google.com/reference/kotlin/com/google/home/HomeDevice.md.txt#setName(kotlin.String))
method to change the name of a device:

```kotlin
mixerDevice.setName("Grendel")
```

Names will be truncated if over the 60 Unicode code point
(character) limit and no errors will be thrown. Developers are responsible for handling long names
and, for example, can decide if they want to inform users names will be truncated.

### Check group membership for a device

A physical device can belong to one or more device groups. To see which
groups a device belongs to, check the
[`GroupMembership`](https://developers.home.google.com/reference/kotlin/com/google/home/google/GroupMembership.md.txt)
trait on the device:

```kotlin
val groupIds = device.trait(GroupMembershipTrait)?.groupObjectIds.orEmpty()
for (groupId in groupIds) {
  println("HomeAPI", "Device belongs to group: $groupId")
}
```

Conversely, you can observe all member devices belonging to a
[`DeviceGroup`](https://developers.home.google.com/reference/kotlin/com/google/home/DeviceGroup.md.txt) by calling the
`devices()` flow on a `DeviceGroup`:

```kotlin
group.devices(enableMultipartDevices = true).collect { members ->
  println("HomeAPI", "Group contains ${members.size} devices")
}
```

To inspect the device types supported by a `DeviceGroup` and send commands to
the group as a single entity, see
[Control a device group](https://developers.home.google.com/apis/android/device/control.md.txt#control-group).