Ten przewodnik jest kontynuacją artykułu Dostęp do urządzeń i ich metadanych na iOS i zawiera dodatkowe przykłady sterowania urządzeniami i uzyskiwania do nich dostępu.
Aby używać określonych typów urządzeń lub cech, takich jak Matter
OnOffTrait, które są używane w wielu przykładach, musisz je zaimportować:
import GoogleHomeSDK
import GoogleHomeTypes
Sprawdzanie, czy cecha obsługuje polecenie
Użyj funkcji supports na poziomie cechy, aby sprawdzić, czy polecenie jest obsługiwane na danym urządzeniu.
Aby na przykład sprawdzić, czy urządzenie obsługuje polecenie toggle cechy Wł./wył.:
// 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") }
Wysyłanie polecenia na urządzenie
Wysyłanie polecenia jest podobne do odczytywania atrybutu stanu z cechy. Aby włączyć lub wyłączyć urządzenie, użyj polecenia przełączania OnOffTrait, które w modelu danych ekosystemu Google Home jest zdefiniowane jako toggle(). Ta metoda zmienia onOff na false, jeśli jest to true, lub na true, jeśli jest to false:
// Calling a command on a trait. do { try await onOffTraitTest.toggle() } catch let _ as HomeError { // Code for handling the exception }
Polecenia mogą zwracać wyjątek, jeśli zostanie wykryty problem z przepływem wykonywania. Jako deweloper musisz użyć bloku do-catch, aby prawidłowo obsługiwać te wyjątki i wyświetlać użytkownikom szczegółowe informacje o przypadkach, w których błędy można naprawić. Nieobsługiwane wyjątki zatrzymują działanie aplikacji i mogą powodować jej awarie.
Możesz też użyć poleceń off() lub on(), aby wyraźnie ustawić stan:
do { try await onOffTraitTest.off() try await onOffTraitTest.on() } catch let _ as HomeError { // Code for handling the exception }
Po wysłaniu polecenia zmiany stanu i jego wykonaniu możesz odczytać stan zgodnie z opisem w sekcji Odczytywanie stanu urządzenia, aby obsłużyć go w aplikacji.
Wysyłanie polecenia z parametrami
Niektóre polecenia mogą używać parametrów, takich jak te na stronie OnOffTrait lub 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 }
Sprawdzanie, czy cecha obsługuje atrybut
Niektóre urządzenia mogą obsługiwać cechę Matter, ale nie konkretny atrybut. Na przykład urządzenie Cloud-to-cloud, które zostało zmapowane na Matter, może nie obsługiwać wszystkich atrybutów Matter. Aby obsłużyć takie przypadki, użyj właściwości isSupported na poziomie cechy, aby sprawdzić, czy atrybut jest obsługiwany na danym urządzeniu.
Aby na przykład sprawdzić, czy urządzenie obsługuje atrybut onOff cechy 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!") }
Niektóre atrybuty mogą mieć wartość null w specyfikacji Matter lub schemacie Cloud-to-cloud smart home. W przypadku tych atrybutów możesz określić, czy wartość nil zwrócona przez atrybut wynika z tego, że urządzenie nie zgłasza tej wartości, czy też wartość atrybutu to faktycznie nil. W tym celu oprócz isSupported użyj isNullable:
// 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))" ) } } }
Aktualizowanie atrybutów cech
Jeśli chcesz zmienić wartość danego atrybutu, a żadne z poleceń cechy tego nie robi, atrybut może obsługiwać jawne ustawienie wartości.
To, czy można zmienić wartość atrybutu, zależy od 2 czynników:
- Czy atrybut jest zapisywalny?
- Czy wartość atrybutu może się zmienić jako efekt uboczny wysłania polecenia cechy?
Te informacje znajdziesz w dokumentacji referencyjnej cech i ich atrybutów.
Dlatego kombinacje właściwości, które określają, jak można zmienić wartość atrybutu, to:
Tylko do odczytu i nie wpływają na nie inne polecenia. Oznacza to, że wartość atrybutu nie ulega zmianie. Na przykład atrybut
currentPositiontaguSwitchTrait.Tylko do odczytu i pod wpływem innych poleceń. Oznacza to, że jedynym sposobem na zmianę wartości atrybutu jest wysłanie polecenia. Na przykład atrybut
currentLevelelementuLevelControlTraitjest tylko do odczytu, ale jego wartość można zmienić za pomocą poleceń takich jakmoveToLevel.Można je zapisywać i nie mają na nie wpływu inne polecenia. Oznacza to, że możesz bezpośrednio zmienić wartość atrybutu za pomocą funkcji
updatecechy, ale nie ma poleceń, które wpływają na wartość atrybutu. Na przykład atrybutWrongCodeEntryLimittaguDoorLockTrait.Można je zapisywać i wpływają na nie inne polecenia. Oznacza to, że możesz bezpośrednio zmienić wartość atrybutu, używając funkcji
updatecechy, a wartość atrybutu może się zmienić w wyniku wysłania polecenia. Na przykład atrybutoccupiedCoolingSetpointelementuThermostatTraitmożna zapisać, ale można go też zaktualizować za pomocą poleceniasetpointRaiseLower.
Przykład użycia funkcji aktualizacji do zmiany wartości atrybutu
Ten przykład pokazuje, jak jawnie ustawić wartość atrybutu DoorLockTrait.wrongCodeEntryLimit.
Aby ustawić wartość atrybutu, wywołaj funkcję update cechy i przekaż jej funkcję aktualizacji, która ustawia nową wartość. Zalecamy najpierw sprawdzić, czy cecha obsługuje dany atrybut.
Na przykład:
if doorLockTraitTest.attributes.$wrongCodeEntryLimit.isSupported { let _ = try await doorLockTraitTest.update { $0.setWrongCodeEntryLimit(3) } }
Sterowanie grupą urządzeń
Oprócz precyzyjnej kontroli nad każdym członkiem grupy przez iterowanie po urządzeniach członków możesz sterować DeviceGroup jako pojedynczą encją. DeviceGroup jest zgodny z protokołem HasParts i udostępnia części DeviceType obsługiwane przez urządzenia w grupie:
await group.part(_:)zwraca pierwsze wystąpienie określonego elementuDeviceType, jeśli grupa go obsługuje, lubnilw przeciwnym razie.try await group.parts(_:)zwraca tablicę wszystkich części najwyższego poziomu pasujących do określonegoDeviceType.
Gdy wywołasz polecenie cechy na typie urządzenia, który jest częścią DeviceGroup, pakiet SDK przekaże polecenie do wszystkich powiązanych urządzeń w grupie, które obsługują tę funkcję, niezależnie od ich połączenia lub transportu (np. Matter lub Cloud-to-cloud).
Atrybuty cech części grupy i obsługa błędów
Kierowanie na część grupy upraszcza typowe przypadki, w których chcesz wysłać idempotentne polecenie (np. włączenie lub wyłączenie światła albo ustawienie poziomu jasności) do grupy. Podczas pracy z atrybutami i poleceniami w części DeviceGroup pamiętaj o tych kwestiach:
- Atrybuty stanu dynamicznego (takie jak atrybut
onOffelementuOnOffTraitlub atrybutcurrentLevelelementuLevelControlTrait) nie są zwykle wypełniane w cesze części grupy, ponieważ urządzenia należące do grupy mogą być w różnych stanach, których nie można połączyć w jedną wartość. Obsługiwane polecenia (oznaczone ikonąsupports(_:), np..moveToLevelWithOnOffw przypadku ściemnianego światła) i wybrane atrybuty funkcji (np.colorTempPhysicalMinMiredsicolorTempPhysicalMaxMiredsw przypadkuColorControlTraitdla kolorowych świateł) są jednak wypełniane, aby aplikacja mogła odpowiednio skonfigurować elementy sterujące interfejsu. - Nie wszystkie polecenia dotyczące cech członków grupy są dostępne w części grupy. W szczególności niedostępne są polecenia, które zwracają wartości.
- Polecenie dotyczące części grupy nie zwraca poszczególnych wyników dla każdego polecenia urządzenia podrzędnego. Aby sprawdzić wyniki poszczególnych poleceń lub wywołać polecenia, które zwracają wartości, wykonaj iterację bezpośrednio na urządzeniach należących do grupy.
- Polecenia wysyłane do części na urządzeniu
DeviceGroupsą wykonywane po zakończeniu całego procesu fanout na urządzeniach członków i zebraniu wszystkich informacji o powodzeniu lub niepowodzeniu poleceń. Polecenie kończy się niepowodzeniem (zwraca błądHomeError) tylko wtedy, gdy nie powiedzie się w przypadku wszystkich powiązanych urządzeń członków lub gdy wszystkie urządzenia docelowe są niedostępne. Jest to sygnalizowane jako niepowodzenie pojedynczego polecenia, które odpowiada składni wywołania pojedynczego polecenia. Jeśli co najmniej 1 urządzenie należące do grupy wykona polecenie, polecenie grupowe zostanie wykonane bez błędu.
Wysyłanie poleceń do części grupy
Aby włączyć wszystkie światła OnOffLightDeviceType w grupie urządzeń:
if let lightPart = await group.part(OnOffLightDeviceType.self),
let onOffTrait = lightPart.matterTraits.onOffTrait,
onOffTrait.supports(.on) {
try await onOffTrait.on()
}
Możesz też sprawdzić kilka powiązanych typów urządzeń (np. wyłączyć dowolny typ urządzenia oświetleniowego w grupie, która obsługuje 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()
}
Przed wysłaniem polecenia możesz sprawdzić obsługę poleceń lub odczytać granice możliwości części grupy (np. sprawdzić .moveToLevelWithOnOff w przypadku części oświetlenia z możliwością ściemniania lub odczytać colorTempPhysicalMinMireds i colorTempPhysicalMaxMireds w przypadku części oświetlenia z temperaturą kolorów):
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: []
)
}