In the Home APIs for Android, observing changes to state in the home is made
possible through the use of
[flows](https://developer.android.com/kotlin/flow)
in Kotlin. Observing changes in structures, rooms, device metadata, and
device state in the Home APIs can be done with any API inheriting from the
[`HomeObjectsFlow`
interface](https://developers.home.google.com/reference/kotlin/com/google/home/HomeObjectsFlow). This is done by
*collecting* from the flow.

When any item in a collection is added, deleted, or modified, the latest
snapshot of the collection is returned.

It is up to the developer to deduce the specific changes by comparing this
snapshot with an older copy. The `id` field provided for [each parent object
type in the Home APIs](https://developers.home.google.com/reference/kotlin/com/google/home/HasId) can be used for
this purpose.

## How to use flows

What follows are some basic examples of collecting from flows in the Home APIs.
For the following examples, an instance of the `Home` must be created before
accessing collections in the home:  

    val context = LocalContext.current
    val homeManager = Home.getClient(context)

### Track changes to a structure

The following changes to a structure trigger this collection:

- Structure [name](https://developers.home.google.com/reference/kotlin/com/google/home/Structure#name())

    homeManager.structures().map { it.firstOrNull() }.collect {
      println("Structure ${it.id} updated to ${it}")
    }

    val structure =  homeManager.structures().list().firstOrNull()!!

### Track changes to a specific device

The following changes to a device trigger this collection:

- [Connectivity state](https://developers.home.google.com/reference/kotlin/com/google/home/ConnectivityState)
- Device [name](https://developers.home.google.com/reference/kotlin/com/google/home/HomeDevice#name())
- [Room](https://developers.home.google.com/reference/kotlin/com/google/home/HomeDevice#room()) membership
- The set of supported [traits](https://developers.home.google.com/reference/kotlin/com/google/home/HasTraits#has(com.google.home.TraitFactory))
- The set of supported [types](https://developers.home.google.com/reference/kotlin/com/google/home/HasDeviceTypes#has(com.google.home.DeviceTypeFactory))

    structure
      .devices()
      .map { devices -> device.filter { it.name == "Bedroom Lamp" }.single() }
      .collect {
        println("The bedroom lamp has changed!")
      }

    val device = structure.devices().list().firstOrNull { it.name == "Bedroom Lamp" }!!

### Track changes to a specific trait on a device

Use any trait supported by the device and the Home APIs. For a full list, see
[`Trait`](https://developers.home.google.com/reference/kotlin/com/google/home/Trait).  

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

        trait?.collect {
          if (it != null) {
            println("Got new state update! ${it.onOff}")
          }
        }

### Track changes to a specific type on a device

The following changes to a device type trigger this collection:

- Changes to any trait within the [generated device
  type](https://developers.home.google.com/reference/kotlin/com/google/home/HasDeviceTypes#type(com.google.home.DeviceTypeFactory))

Use any Matter device type supported by the Home APIs. For
a full list, see [`DeviceType`](https://developers.home.google.com/reference/kotlin/com/google/home/DeviceType).  

    device.type(DimmableLightDevice).collect { type ->
        println("Got new state update! ${type.trait(LevelControl)?.currentLevel}")
    }

### Track changes to a room in a structure

The following changes to a room trigger this collection:

- Room [name](https://developers.home.google.com/reference/kotlin/com/google/home/Room#name())
- [Structure](https://developers.home.google.com/reference/kotlin/com/google/home/Room#structure()) membership

To track when devices are added or removed from a room, use the [`devices()`
flow](https://developers.home.google.com/apis/android/device/monitor#device).  

    structure.rooms().collect {
      println("Got a new updated set of rooms!")

      for (room in it) {
        println("Got room $room")
      }
    }

## Subscribe to events

In the Home APIs, events are used to detect changes in the state of
a device.
| **Important:** Ideally, a developer could rely on devices and apps to send the expected events according to the Matter specification. However, device manufacturers aren't required to send Matter events, so in these cases, to monitor device state, you should use the techniques described in [Observe state
| changes](https://developers.home.google.com/apis/observe-state).

To subscribe to events on a specific device, call one of the three
[`HomeDevice`](https://developers.home.google.com/reference/kotlin/com/google/home/HomeDevice).[`events`](https://developers.home.google.com/reference/kotlin/com/google/home/HasEvents#events(com.google.home.EventFactory))
functions, each of which returns a`Flow<Event>`:

1. `events(event: EventFactory<T>)` returns a flow for a specific kind
   of event:

       val eventFlow = homeDevice.type(DoorLockDevice).first().events(DoorLock.DoorLockAlarmEvent)

2. `events(trait: TraitFactory<T>)` returns a flow of all events
   sent by a trait:

       val eventflow = homeDevice.type(DoorLockDevice).first().events(DoorLock)

3. `events()` returns a flow of events available for the object:

       val eventflow = homeDevice.type(DoorLockDevice).first().events()

To consume events from a flow, use the `flow.collect()` function:  

    eventflow.collect { event ->
      if (event != null) {
        logger.atInfo().log("Received event %s", event)
        // do something
      }
    }

## Subscribe to entity relation events

You can listen for events that are emitted every time an entity (such as a
structure, room, device, or automation) is added, removed, or updated. These
events are instances of
[`HomeObjectChangeEvent`](https://developers.home.google.com/reference/kotlin/com/google/home/HomeObjectChangeEvent)
and carry the ID of the entity that changed.
| **Note:** These events don't originate as Matter events, but directly from the Device and Structure APIs.

To acquire a stream that produces the events you want, call the
[`stream()`](https://developers.home.google.com/reference/kotlin/com/google/home/HomeObjectsFlow#stream()) method
on the [`HomeObjectsFlow<T>`](https://developers.home.google.com/reference/kotlin/com/google/home/HomeObjectsFlow)
produced by the corresponding Flow method:

| Entity | Interface | Flow Method |
|---|---|---|
| [Structure](https://developers.home.google.com/apis/android/device/reference/kotlin/com/google/home/Structure) | [HasStructures](https://developers.home.google.com/reference/kotlin/com/google/home/HasStructures) | [structures()](https://developers.home.google.com/reference/kotlin/com/google/home/HasStructures#structures()) |
| [Room](https://developers.home.google.com/apis/android/device/reference/kotlin/com/google/home/Room) | [HasRooms](https://developers.home.google.com/reference/kotlin/com/google/home/HasRooms) | [rooms()](https://developers.home.google.com/reference/kotlin/com/google/home/HasRooms#rooms()) |
| [HomeDevice](https://developers.home.google.com/apis/android/device/reference/kotlin/com/google/home/HomeDevice) | [HasHomeDevices](https://developers.home.google.com/reference/kotlin/com/google/home/HasHomeDevices) | [devices()](https://developers.home.google.com/reference/kotlin/com/google/home/HasHomeDevices#devices()) |
| [Automation](https://developers.home.google.com/apis/android/device/reference/kotlin/com/google/home/Automation) | [HasAutomations](https://developers.home.google.com/reference/kotlin/com/google/home/HasAutomations) | [automations()](https://developers.home.google.com/reference/kotlin/com/google/home/HasAutomations#automations()) |
[*Table: Event streams*]

For example, here's how you can handle changes to devices:  

```kotlin
val devicesStream = home.devices().stream()

// Collect and react to device changes.
devicesStream.collect { deviceEvent ->
  when (deviceEvent) {
    is HomeObjectAddedEvent ->
      println("New device now available with id: ${deviceEvent.id}")
    is HomeObjectUpdatedEvent -> println("Device ${deviceEvent.id} has been updated")
    is HomeObjectRemovedEvent -> println("Device is removed from your account")
    else -> {}
  }
}
```