Access devices and device metadata

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

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:

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

For more information, see Data model.

Error handling

Any method in the Home APIs can throw a HomeException, so we recommend that you use a try-catch block to catch HomeException on all calls.

When handling HomeException, check its code and message fields to learn what went wrong.

Any unhandled exceptions will result in your app crashing.

For more information, see Error handling.

See Send a command to a device for an example.

Sample calls

Get a list of devices

With structure available, a devices() call returns a Flow of devices accessible to you from that structure:

// 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, states for each device are accessible, and supported commands can be sent to the device.

Read a device state

Let's 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:

// 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 to learn more about the Kotlin flow function.

Invalidate state in a trait subscription

The TraitStateInvalidation interface 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:

val generalDiagnosticsTrait = device.trait(GeneralDiagnostics).first()
generalDiagnosticsTrait.forceRead()

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:

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

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

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

Get a list of devices with a specific trait

The filter 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:

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

See the Trait interface 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:

// 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 for a full list of device types available in the Home APIs.

Get the Vendor ID or Product ID for a device

The BasicInformation trait includes information like Vendor ID, Product ID, Product Name and the Serial Number for a device:

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

Identify Cloud-to-cloud devices

If you are a device maker and build Cloud-to-cloud devices, in order to identify your Cloud-to-cloud devices through the BasicInformation trait, you can include these string fields in their SYNC response:

  • The Connectivity Standards Alliance (CSA) 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 CSA 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:

{
  "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.

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

First, get the type(s) of the device using type(), then determine which is the primary type:

val types = device.types().first()
val primaryType = types.first { it.metadata.isPrimaryType }

Check if a trait is online

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

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 do not 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.

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.

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.

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.

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.

API list

Once an instance of Home is created, the following Device APIs are accessible through it:

API Description
devices() Get all the devices in all structures on the Google Account. Returns a HomeObjectsFlow that provides further retrieval and filtering options.

Once you have a HomeDevice, the following APIs are accessible through it:

API Description
allCandidates() Returns all automation candidates for the device and its children.
candidates() Returns all automation candidates for the device.
connectivityStateChanged The most recent time the state of the device changed.
events(event) Gets a flow of a specific Event.
events(trait) Gets a flow of all Events by this Trait.
events(traits) Gets a flow of all Events by these Traits.
getSourceConnectivity(trait) Get metadata for a particular trait. Returns a SourceConnectivity.
has(trait) Check if the current requested trait is supported by the device.
has(type) If the device supports the type provided.
id The unique system ID of the device.
isInRoom If the device is in a room.
isInStructure If the device is in a structure.
isMatterDevice If the device is backed by Matter.
name The user-provided name of the device.
room() The room the device is assigned to. Returns a Room.
roomId The ID of the room the device is assigned to. Returns an Id.
sourceConnectivity The source connectivity of the device, representing aggregated connectivity states and network locality of the device's traits.
structure() The structure the device is assigned to. Returns a Structure.
structureId The ID of the structure the device is assigned to. Returns an Id.
type(type) Get the type definition with the traits populated (when available) for direct access. Always returns an up-to-date snapshot of the traits.
types() Get a list of all types available on the device.