Structure APIs may be accessed through the Home APIs for iOS.
To work with the Structure APIs, first import the GoogleHomeSDK
package into
your app:
import GoogleHomeSDK
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.
Structure API
Home
represents the Home graph, and is the entry point to the Structure API.
It provides references to structures, rooms, and devices.
Structure
represents a structure in your Home graph. It provides access to
structure metadata such as id
and name
.
Use structures()
to
get all structures in your account. The structures are returned in the form of a
Query
, which offers a choice
of ways of consuming its data:
API | Description |
---|---|
stream() |
Returns a Publisher that emits each object individually as changes take place. |
batched() |
Returns a Publisher that emits the current result as a Set of objects. Each emitted Set represents the current state of the object graph. |
list() |
Returns the current result as a Set of objects. |
The structures().list()
call may not immediately return a valid set of
structures. If your app is reactive and calls stream()
to subscribe to
all structure changes to drive the UI, a valid list of structures should
eventually be returned. There are other situations where an empty structure list
could be returned, for example if the user's phone loses connectivity or if the
user has revoked permissions to your app. You should be sure to handle these
cases in your app.
@Published public private(set) var structures: [Structure] = []
private var structuresCancellable: AnyCancellable?
self.structuresCancellable = home
.structures()
.batched()
.receive(on: DispatchQueue.main)
.map { Array($0) }
.catch {
Logger.error("Failed to load structures: \($0)")
return Just([Structure]())
}
.assign(to: \.structures, on: self)
Sample Structure calls
Get a set of structures
Calling list()
on a Query<Structure>
returns the most recent Set of
elements:
// Get a stream of all structures accessible to the user let allStructuresChanges = try await self.home.structures() let allStructures = try? await allStructuresChanges.list()
When designing a reactive app, you'll want to use batched()
and stream()
calls rather than list()
, because these automatically produce data when the
home graph changes.
Get structure properties
With the list of structures in hand, you can access the properties for them:
// Get a stream of changes taking place on a structure. let structureChanges = try await home.structures().list().filter { $0.id == structureID } // Get a snapshot of the structure. let structure = try await structureChanges.first! // Get structure properties print("id \(structure.id) ") print("name \(structure.name) ")
Find a structure by name
If you know the name of a structure, you can also access it using the name
property:
do { structure1 = try await home.structures().list().first(where: { $0.name == "Main House" }) } catch let error as HomeError { // Code for handling the exception }
From there, properties, rooms, and devices for each structure are accessible.
Work with multiple structures
To use more than one structure, get a separate reference to each structure:
var structure1: Structure! var structure2: Structure! do { structure1 = try await home.structures().list().first(where: { $0.name == "Main House" }) } catch let error as HomeError { // Code for handling the exception } do { structure2 = try await home.structures().list().first(where: { $0.name == "Guest Cottage" }) } catch let error as HomeError { // Code for handling the exception }
Rooms
A room contains a group of devices. A room is always part of a structure and a structure may have multiple rooms. Removing a room from a structure does not remove the devices in that room from the structure. However, if the room is deleted, the devices in that room become unassigned.
Use Home.rooms()
to
retrieve all the rooms in the account, then use roomID = device.roomID
to
display the corresponding devices in each room.
self.home.rooms().batched()
.combineLatest(self.home.devices().batched())
.receive(on: DispatchQueue.main)
.catch { error in
Logger.error("Failed to load rooms and devices: \(error)")
return Just((Set<Room>(), Set<HomeDevice>()))
}
.map { rooms, devices in
var devicesByRoom = [Room: [HomeDevice]]()
for room in rooms where room.structureID == currentStructureID {
devicesByRoom[room] = devices.filter { $0.roomID == room.id }
}
return devicesByRoom
}.assign(to: &self.$devicesByRoom)
Sample Room calls
Get a list of rooms
Using the Home
class, you can get a list of rooms and access the
properties for them:
let allRoomsChanges = self.home.rooms() let allRooms = try await allRoomsChanges.list() let room = allRooms.first! XCTAssertTrue(allRooms.contains(room)) print("id \(room.id) ") print("name \(room.name) ")
Create a room
To create a new room in a Structure
:
let testName = "Test Room Name" var newRoom: Room! do { newRoom = try await structure.createRoom(name: testName) XCTAssertNotNil(newRoom) } catch let error as HomeError { // Code for handling the exception }
Delete a room
Or, alternatively, you can delete a room:
val roomToDelete = structure.rooms().list().filter { it.name == "room_id1" }.firstOrNull() structure.deleteRoom(roomToDelete!!)
You can also delete a room using its ID:
let roomToDelete = allRooms.first(where: { $0.id == room.id }) if let roomToDelete1 = roomToDelete { do { try await structure.deleteRoom(roomToDelete1) } catch let error as HomeError { // Code for handling the exception } }
If a room with devices is deleted, the devices will still be in the structure but no longer assigned to a room.
Move devices to a different room
Structure
also lets you move a device to a different room:
do { try await structure.move(device: light, to: room) } catch let error as HomeError { // Code for handling the exception }
API list
Once an instance of
Home
is created, the
following Structure APIs are accessible through it:
API | Description |
---|---|
devices() |
Get all devices visible to this account. |
device(id:) |
Get a Publisher for a specified device that emits the current state and again on any future state updates. |
structures() |
Get all the structures on the Google Account. Returns a Query<Structure> that provides further retrieval and filtering options. |
structure(id:) |
Get the structure with the matching ID. |
rooms() |
Get all the rooms on the Google Account. Returns a Query<strRoom> that provides further retrieval and filtering options. |
room(id:) |
Get a Publisher for a specified room that emits the current state and again on any future state updates. |
The Structure
has the following
APIs:
API | Description |
---|---|
deleteRoom(id:) |
Delete a room with the room ID. |
id |
The unique system ID of the structure. |
move(device:, to:) |
Move a device to a different room in the structure. |
move(device:, to:) |
Move the device with the given ID to the room with given ID. |
move(devices:, to:) |
Moves the given devices to the given room. |
move(devices:, to:) |
Moves the devices with given IDs to the room with given ID. |
name |
The user-provided name of the structure. |
Room
has the following APIs:
API | Description |
---|---|
id |
The unique system ID of the room. |
name |
The user-provided name of the room. |
structureID |
The unique system ID of the structure to which the room belongs. |