Это руководство продолжает статью Доступ к устройствам и их метаданным на iOS и содержит дополнительные примеры управления устройствами и доступа к ним.
Чтобы использовать определенные типы устройств или характеристики, например Matter
OnOffTrait, которые используются во многих примерах, их необходимо импортировать:
import GoogleHomeSDK
import GoogleHomeTypes
Как проверить, поддерживает ли свойство команду
Используйте функцию supports на уровне типажа, чтобы проверить, поддерживается ли команда для определенного устройства.
Например, чтобы проверить, поддерживает ли устройство команду toggle типа On/Off, выполните следующий запрос:
// Check if the OnOff trait supports the toggle command. if onOffTraitTest.supportsToggleCommand { print("onOffTrait supports toggle command") } else { print("onOffTrait does not support stateful toggle command") }
Как отправить команду на устройство
Отправка команды похожа на чтение атрибута состояния из типажа. Чтобы включить или выключить устройство, используйте команду Toggle (OnOffTrait), которая в модели данных экосистемы Google Home определяется как toggle(). Этот метод меняет значение onOff на false, если оно равно true, или на true, если оно равно false:
// Calling a command on a trait. do { try await onOffTraitTest.toggle() } catch let _ as HomeError { // Code for handling the exception }
Если при выполнении команды возникнет проблема, может появиться исключение. Разработчикам следует использовать блок do-catch, чтобы правильно обрабатывать эти исключения и показывать пользователям подробную информацию о том, как устранить ошибки. Необработанные исключения останавливают работу приложения и могут приводить к сбоям.
Вы также можете использовать команды off() или on(), чтобы явно задать статус:
do { try await onOffTraitTest.off() try await onOffTraitTest.on() } catch let _ as HomeError { // Code for handling the exception }
После отправки команды на изменение состояния и ее выполнения вы можете прочитать состояние, как описано в разделе Чтение состояния устройства, чтобы обработать его в своем приложении.
Как отправить команду с параметрами
В некоторых командах могут использоваться параметры, например в OnOffTrait или LevelControlTrait:
offWithEffect
// Turn off the light using the DyingLight effect. do { try await onOffTraitTest.offWithEffect( effectIdentifier: Matter.OnOffTrait.EffectIdentifierEnum.dyingLight, effectVariant: 0 ) } catch let _ as HomeError { // Code for handling the exception }
moveToLevel
// Change the brightness of the light to 50% do { try await levelControlTraitTest.moveToLevel( level: UInt8(127), transitionTime: 0, optionsMask: Matter.LevelControlTrait.OptionsBitmap(), optionsOverride: Matter.LevelControlTrait.OptionsBitmap() ) } catch let _ as HomeError { // Code for handling the exception }
Как проверить, поддерживает ли функция атрибут
Некоторые устройства могут поддерживать определенную функцию (Matter), но не поддерживать конкретный атрибут. Например, устройство Cloud-to-cloud, сопоставленное с типом Matter, может не поддерживать все атрибуты Matter. Чтобы обрабатывать такие случаи, используйте свойство isSupported на уровне типажа. Оно позволяет проверить, поддерживается ли атрибут для определенного устройства.
Например, чтобы проверить, поддерживает ли устройство атрибут onOff типа On/Off, выполните следующий запрос:
// Check if the OnOff trait supports the onOff attribute. if onOffTrait.attributes.$onOff.isSupported { print("onOffTrait supports onOff state") } else { print("onOffTrait is for a command only device!") }
Некоторые атрибуты могут иметь значение NULL в спецификации Matter или схеме Cloud-to-cloud smart home. Для таких атрибутов вы можете определить, возвращается ли значение nil из-за того, что устройство не сообщает значение, или же значение атрибута действительно равно nil. Для этого используйте isNullable в дополнение к isSupported:
// Check if a nullable attribute is set or is not supported. if let deviceType = await device.types.get(OnOffLightDeviceType.self) { if let onOffTrait = deviceType.traits[Matter.OnOffTrait.self] { if onOffTrait.attributes.startUpOnOff == nil { if onOffTrait.attributes.$startUpOnOff.isSupported { print( "onOffTrait supports startUpOnOff and it is nil. Check the spec for the contextual meaning." ) } else { print("onOffTrait does not support startUpOnOff!") } } else { print( "onOffTrait supports startUpOnOff and it is set to \(String(describing: onOffTrait.attributes.startUpOnOff))" ) } } }
Обновить атрибуты признака
Если вы хотите изменить значение определенного атрибута, но ни одна из команд типажа этого не делает, атрибут может поддерживать явную установку своего значения.
Возможность изменить значение атрибута зависит от двух факторов:
- Доступен ли атрибут для записи?
- Может ли значение атрибута измениться в результате отправки команды trait?
Эту информацию можно найти в справочной документации по типажам и их атрибутам.
Таким образом, сочетания свойств, определяющие, как может быть изменено значение атрибута, следующие:
Доступно только для чтения и не зависит от других команд. Это означает, что значение атрибута не меняется. Например, атрибут
currentPositionтегаSwitchTrait.Доступно только для чтения и зависит от других команд. Это означает, что значение атрибута может измениться только в результате отправки команды. Например,
currentLevelатрибут объектаLevelControlTraitдоступен только для чтения, но его значение можно изменить с помощью команд, таких какmoveToLevel.Доступно для записи и не зависит от других команд. Это означает, что вы можете напрямую изменить значение атрибута, используя функцию
updateтипа, но нет команд, которые повлияют на значение атрибута. Например, атрибутWrongCodeEntryLimitтегаDoorLockTrait.Доступно для записи и зависит от других команд. Это означает, что вы можете напрямую изменить значение атрибута с помощью функции
update, а также значение атрибута может измениться в результате отправки команды. Например, атрибутoccupiedCoolingSetpointобъектаThermostatTraitможно не только задать, но и обновить с помощью командыsetpointRaiseLower.
Пример использования функции update для изменения значения атрибута
В этом примере показано, как явно задать значение атрибута DoorLockTrait.wrongCodeEntryLimit.
Чтобы задать значение атрибута, вызовите функцию update и передайте ей функцию обновления, которая задает новое значение. Рекомендуется сначала проверить, поддерживает ли типаж атрибут.
Пример:
if doorLockTraitTest.attributes.$wrongCodeEntryLimit.isSupported { let _ = try await doorLockTraitTest.update { $0.setWrongCodeEntryLimit(3) } }
Как управлять группой устройств
Вы можете не только управлять каждым устройством в группе по отдельности, перебирая их, но и контролировать DeviceGroup как единое целое. DeviceGroup соответствует протоколу HasParts и предоставляет части DeviceType, поддерживаемые устройствами в группе:
await group.part(_:)возвращает первый экземпляр указанногоDeviceType, если группа его поддерживает, илиnilв противном случае.try await group.parts(_:)возвращает массив всех частей верхнего уровня, соответствующих указанномуDeviceType.
Когда вы вызываете команду для типа устройства, входящего в DeviceGroup, SDK передает ее всем связанным устройствам в группе, которые поддерживают эту функцию, независимо от их подключения или транспорта (например, Matter или Cloud-to-cloud).
Атрибуты признаков частей группы и обработка ошибок
Таргетинг на часть группы упрощает распространенные случаи, когда вы хотите отправить идемпотентную команду (например, включить или выключить свет или установить уровень яркости) по всей группе. При работе с функциями и командами в разделе DeviceGroup учитывайте следующее:
- Атрибуты динамического состояния (например, атрибут
onOffэлементаOnOffTraitили атрибутcurrentLevelэлементаLevelControlTrait), как правило, не заполняются в характеристике части группы, поскольку устройства, входящие в группу, могут находиться в разных состояниях, которые нельзя объединить в одно значение. Однако поддерживаемые команды (проверяются с помощьюsupports(_:), например.moveToLevelWithOnOffдля светильника с регулируемой яркостью) и некоторые атрибуты возможностей (например,colorTempPhysicalMinMiredsиcolorTempPhysicalMaxMiredsдляColorControlTraitу цветных светильников) заполняются, чтобы ваше приложение могло правильно настроить элементы управления пользовательского интерфейса. - Не все команды, доступные для характеристик участников группы, доступны для группы. В частности, недоступны команды, возвращающие значения.
- Команда для группы не возвращает отдельные результаты для каждой команды, отправленной на устройство участника. Чтобы проверить результаты отдельных команд или вызвать команды, возвращающие значения, выполните итерацию по устройствам, входящим в группу.
- Команды, отправленные на часть в
DeviceGroup, выполняются после того, как завершится разветвление на устройствах-участниках и будут собраны все сведения об успешных и неудачных попытках выполнения команд. Команда не выполняется (выдает ошибкуHomeError), только если она не выполняется для каждого связанного устройства или если все целевые устройства недоступны. Это отображается как сбой одной команды, соответствующий синтаксису вызова одной команды. Если хотя бы одно устройство выполнит команду, она будет считаться выполненной без ошибок.
Как отправлять команды группе
Чтобы включить все светильники OnOffLightDeviceType в группе устройств:
if let lightPart = await group.part(OnOffLightDeviceType.self),
let onOffTrait = lightPart.matterTraits.onOffTrait,
onOffTrait.supports(.on) {
try await onOffTrait.on()
}
Вы также можете проверить несколько связанных типов устройств (например, выключить все осветительные приборы в группе, поддерживающей OnOffTrait):
func onOffTrait(in group: DeviceGroup) async -> Matter.OnOffTrait? {
if let light = await group.part(OnOffLightDeviceType.self) {
return light.matterTraits.onOffTrait
}
if let light = await group.part(DimmableLightDeviceType.self) {
return light.matterTraits.onOffTrait
}
if let light = await group.part(ColorTemperatureLightDeviceType.self) {
return light.matterTraits.onOffTrait
}
if let light = await group.part(ExtendedColorLightDeviceType.self) {
return light.matterTraits.onOffTrait
}
return nil
}
if let trait = await onOffTrait(in: group) {
try await trait.off()
}
Вы можете проверить поддержку команд или прочитать границы возможностей для части группы перед отправкой команды (например, проверить .moveToLevelWithOnOff для части диммируемого света или прочитать colorTempPhysicalMinMireds и colorTempPhysicalMaxMireds для части света с цветовой температурой):
if let dimmableLight = await group.part(DimmableLightDeviceType.self),
let levelTrait = dimmableLight.matterTraits.levelControlTrait,
levelTrait.supports(.moveToLevelWithOnOff) {
try await levelTrait.moveToLevelWithOnOff(
level: 127,
transitionTime: nil,
optionsMask: [],
optionsOverride: []
)
}
if let colorLight = await group.part(ColorTemperatureLightDeviceType.self),
let colorTrait = colorLight.matterTraits.colorControlTrait,
let minMireds = colorTrait.attributes.colorTempPhysicalMinMireds,
let maxMireds = colorTrait.attributes.colorTempPhysicalMaxMireds {
let midMireds = UInt16((UInt32(minMireds) + UInt32(maxMireds)) / 2)
try await colorTrait.moveToColorTemperature(
colorTemperatureMireds: midMireds,
transitionTime: 0,
optionsMask: [],
optionsOverride: []
)
}