Мониторинг состояния устройства на iOS

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

При добавлении, удалении или изменении любого элемента коллекции возвращается последний снимок коллекции.

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

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

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

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

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

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

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

Ниже приведены несколько базовых примеров работы с издателями в API Home. Для этих примеров необходимо создать экземпляр 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 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 , поддерживаемый Home API. Полный список см. в разделе 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
    Logger.error("Error getting FanDeviceType: \(error)")
    return Empty<FanDeviceType, Never>().eraseToAnyPublisher()
  }
  .sink { [weak self] fanDeviceType in
    self?.fanDeviceType = fanDeviceType
    self?.updateTileInfo()
  }
}