Как отслеживать состояние устройств iOS

В API Home для iOS отслеживать изменения состояния в доме можно с помощью фреймворка Combine в Swift. Отслеживать изменения в структурах, комнатах, метаданных устройств и состоянии устройств в API Home можно с помощью любого API, используя HomeDevice. Для этого нужно подписаться на издателей, которые предоставляют значения из асинхронных событий.

Когда в подборку добавляется, удаляется или изменяется какой-либо объект, возвращается последний снимок подборки.

Разработчик может определить, какие именно изменения произошли, сравнив этот снимок с более ранней копией. Для этого можно использовать поле id, которое есть у каждого родительского объекта в Home API.

Как развернуть необязательные объекты

Если объект необязательный, используйте if let или guard, чтобы безопасно извлечь объект. Не используйте !, поскольку !его следует применять только в том случае, если разработчик уверен, что объект не может быть нулевым.

Входной параметр structureID в примере определен как String?, то есть это необязательная строка, которая может быть пустой. Эта функция находит объект Structure на основе входных данных в structureID.

Вот как мы рекомендуем обрабатывать необязательные объекты:

func structure(structureID: String?) -> Structure? {
    guard let structureID else { return nil }
    return structures.first { $0.id == structureID }
  }

Как использовать издателей

Ниже приведены основные примеры работы с издателями в Home API. В приведенных ниже примерах необходимо создать экземпляр Home.

var home: Home?

Перед тем как получить доступ к коллекциям, убедитесь, что они распакованы, поскольку они необязательны:

guard let home else { return nil }

Как отслеживать изменения в структуре

Следующие изменения в структуре вызывают сбор данных:

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.name)")
    }
  }

Как отслеживать изменения на определенном устройстве

Коллекция запускается при следующих изменениях на устройстве:

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

Как отслеживать изменения определенного свойства устройства

Используйте любой признак, поддерживаемый устройством и API Google Home. Полный список приведен в статье 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)")
    }
  }

Как отслеживать изменения определенного типа на устройстве

Сбор данных запускается при следующих изменениях типа устройства:

Используйте любой тип устройства Matter, поддерживаемый API Home. Полный список приведен в разделе 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)")
    }
  }

Как отслеживать изменения в комнате в структуре

Коллекция запускается при следующих изменениях в переговорной комнате:

Чтобы отслеживать, когда устройства добавляются в комнату или удаляются из нее, используйте devices() запрос.

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

Как оформить подписку на события

В API Home события используются для обнаружения изменений в состоянии устройства.

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