Device APIs may be accessed through the Home APIs for iOS. Import the following packages into your app:
import GoogleHomeSDK
import GoogleHomeTypes
For more information, see Data model on iOS.
Error handling
Some methods in the Home APIs throw a
HomeError
, so we recommend that you use a do-catch
block to catch
HomeError
on those calls.
When handling HomeError
, check its code
and message
fields to learn what went wrong.
Any unhandled errors 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 a reference to the Home
object, invoke
devices()
to get a
Query
of accessible
devices.
Call the Query
's
batched()
method, which emits a Set reflecting the current state of the Home with every
device metadata change. Or call
Query.list()
to get a
snapshot of available devices. This is a convenience method that subscribes to
the batched()
stream and returns the first emitted value.
Query.stream()
produces a stream that emits new values on device metadata changes such as its
name, room, or structure. Internally, this uses batched()
and only emits
the changed properties.
// Get a list of all devices accessible to the user let homeDevices = try await self.home.devices().list()
From there, states for each device are accessible, and supported commands can be sent to the device.
Get the device's types
To get device types associated with a device, read the
device's types
property, which returns a
DeviceTypeController
.
Call DeviceTypeController.subscribe(_:)
to subscribe to updates for a
particular device type:
let devices = try await self.home.devices().list() if let device = devices.first(where: { $0.id == myDeviceId }) { var receivedUpdate1 = false var receivedUpdate2 = false device.types.subscribe(OnOffLightDeviceType.self) .assertNoFailure() .sink { device in if !receivedUpdate1 { receivedUpdate1 = true Task { try await device.matterTraits.onOffTrait?.on() } return } if !receivedUpdate2 { receivedUpdate2 = true return } fatalError("Received unexpected update") } }
If the device doesn't support the specified device type, it returns an Empty
Publisher
that completes immediately.
If the device supports a specific device type, you can get a handle to that
type by calling get()
:
if let device = devices.first(where: { $0.id == myDeviceId }) { let deviceType = await device.types.get(OnOffLightDeviceType.self) }
If the device doesn't support the specified type, it returns nil
.
Call
DeviceTypeController.subscribeAll()
to get a Publisher
of
DeviceTypeCollection
.
This class lets you check to see if the device has a particular device
type:
if let device = devices.first(where: { $0.id == myDeviceId }) { device.types.subscribeAll() .assertNoFailure() .sink { types in let lightDeviceType = types[OnOffLightDeviceType.self] let fanDeviceType = types[FanDeviceType.self] } }
Get a device type trait
Device types are the 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.
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, reference a trait through one of the two trait
collections on each device type.
For standard traits, that is, those that are analogous to
Matter standard clusters, use matterTraits
. For example,
to get a specific trait for the Dimmable Light device type:
if let dimmableLightDeviceType = await device.types.get(DimmableLightDeviceType.self) { // Accessing standard trait on the type. let levelControlTrait = dimmableLightDeviceType.matterTraits.levelControlTrait.self }
For Google traits, use googleTraits
:
if let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) { // Accessing Google trait on the type. let doorbellPressTrait = doorbellDeviceType.googleTraits.doorbellPressTrait.self }
To access a manufacturer-specific trait, reference it through the traits
property, but preface it with the manufacturer's package name:
let deviceType = await device1?.types.get(OnOffLightDeviceType.self) // Accessing custom trait on the type. if let spinnerTrait = deviceType?.traits[ExampleOrganization.SpinnerTrait.self] { let rpmVal = spinnerTrait.attributes.rpm }
Read a device state
Look at this example of checking the OnOff
attribute from the device's
On/Off trait:
let lightDevices = devices.filter { $0.types.contains(OnOffLightDeviceType.self) } let light1 = lightDevices.first let lightDeviceTypeOptional = await light1?.types.get(OnOffLightDeviceType.self) if let onOffTrait = lightDeviceTypeOptional?.matterTraits.onOffTrait { let onOffVal = onOffTrait.attributes.onOff }
Get a list of devices with a specific trait
To get a list of devices that have a specific trait, you need to iterate over the devices, each device's device types, and each device type's traits. For example, to get a list of devices in the home that all have the On/Off trait:
// Get all light devices that support levelControl var levelControlDevices: [HomeDevice] = [] var allDevices = try await home.devices().list() for device in allDevices { if let deviceType = await device.types.get(OnOffLightDeviceType.self) { if deviceType.traits.contains(Matter.LevelControlTrait.self) { levelControlDevices.append(device) } } }
See Trait index on iOS 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) let lightDevices = try await self.home.devices().list().compactMap { $0.types.contains(DimmableLightDeviceType.self) || $0.types.contains(OnOffLightDeviceType.self) || $0.types.contains(ColorTemperatureLightDeviceType.self) || $0.types.contains(ExtendedColorLightDeviceType.self) }
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.
See the Supported device types on iOS for a full list of device types and their traits that are available in the Home APIs.
Get the Vendor Name, Vendor ID or Product ID for a device
The BasicInformationTrait
trait includes information like Vendor ID, Product ID, Product Name and the
Serial Number for a device:
guard let vendorName = basicInfoTrait.attributes.vendorName else { fatalError("Failed to get vendorName") } guard let vendorID = basicInfoTrait.attributes.vendorID else { fatalError("Failed to get vendorID") } guard let productID = basicInfoTrait.attributes.productID else { fatalError("Failed to get 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 BasicInformationTrait
, 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 haven't 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 to see whether a device type is the device's primary type.
if let deviceType = await device?.types.get(HumiditySensorDeviceType.self) { if deviceType.metadata.isPrimaryType { print("Humidity Sensor is the primary type on this device.") } else { print("Humidity Sensor isn't the primary type on this device.") } }
Check if a trait is online
Read the connectivityState
property to check a trait's connectivity:
let levelControlConnectivity = levelControlTrait.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.
let lightConnectivity = dimmableLightDeviceType.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.
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.
let levelControlLocality = levelControlTrait.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.
let lightLocality = dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality
A state of mixed
may be observed in a similar scenario
as that of partiallyOnline
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 |
---|---|
device(id:) |
Returns a Publisher for the specified device that emits device state whenever it changes. |
devices() |
Get all the devices in all structures on the Google Account. Returns a Query<HomeDevice> that provides further retrieval and filtering options. |
Once you have a
HomeDevice
, the following
APIs are accessible through it:
API | Description |
---|---|
id |
The unique system ID of the device. |
name |
The user-provided name of the device. |
structureID |
The ID of the structure the device is assigned to. Returns a String? . |
roomID |
The ID of the room the device is assigned to. Returns a String? . |
types |
Get a specific type or all available types on the device. |
isMatterDevice |
If the device is backed by Matter. |
sourceConnectivity |
The source connectivity of the device, representing aggregated connectivity states and network locality of the device's traits. |