Monitor device state on iOS

In the Home APIs for iOS, observing changes to state in the home is made possible through the use of the Combine framework in Swift. Observing changes in structures, rooms, device metadata, and device state in the Home APIs can be done with any API using HomeDevice. This is done by subscribing to publishers exposing values from asynchronous events.

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 can be used for this purpose.

How to use publishers

What follows are some basic examples of working with publishers in the Home APIs. For the following examples, an instance of the Home and Structure must be created before accessing collections:

var home: Home!
var structure: Structure!

Track changes to a structure

The following changes to a structure trigger this collection:

home.structures.batched()
  .compactMap { $0.first(where: { $0.id = myStructureID} }
  .removeDuplicates()
  .sink { structure in
    if let structure = structure {
      print("Structure \(structure.id) updated to \(structure)")

Track changes to a specific device

The following changes to a device trigger this collection:

home.devices().batched()
  .compactMap { deviceList -> HomeDevice? in
    deviceList.filter { $0.name == "Bedroom Lamp"}.first
  }
  .removeDuplicates()
  .sink { lampDevice in
    if lampDevice != nil {
      print("The bedroom lamp has changed!")
    }
  }

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.

device.types.subscribe(OnOffLightDeviceType.self)
  .compactMap { $0.matterTraits.onOffTrait }
  .removeDuplicates()
  .sink { onOffState in
    if let onOffState = onOffState {
      print("Got new state update: \(onOffState.onOff)")
    }
  }

Track changes to a specific type on a device

The following changes to a device type trigger this collection:

Use any Matter device type supported by the Home APIs. For a full list, see DeviceType.

device.types.subscribe(DimmableLightDeviceType.self)
  .compactMap { $0.matterTraits.levelControlTrait }
  .removeDuplicates()
  .sink { dimmableLightDevice in
    if let dimmableLightDevice = dimmableLightDevice
      print("Got new state update! \(levelControlTrait.currentLevel)")
    }
  }

Track changes to a room in a structure

The following changes to a room trigger this collection:

To track when devices are added or removed from a room, use the devices() query.

home.rooms().batched()
  .sink { rooms in
    print("Got a new updated set of rooms!")
    for room in rooms {
      print("Got room #\(room.name)")
    }
  }

Subscribe to events

In the Home APIs, events are used to detect changes in the state of a device.

self.cancellable = self.device.types.subscribe(FanDeviceType.self)
  .receive(on: DispatchQueue.main)
  .catch { error in
    Logger.error("Error getting FanDeviceType: \(error)")
    return Empty<FanDeviceType, Never>().eraseToAnyPublisher()
  }
  .sink { [weak self] fanDeviceType in
    self?.fanDeviceType = fanDeviceType
    self?.updateTileInfo()
  }
}