คู่มือนี้เป็นส่วนต่อจากเข้าถึงอุปกรณ์และข้อมูลเมตาของอุปกรณ์ใน iOS และจะแนะนำตัวอย่างเพิ่มเติมเกี่ยวกับการควบคุมและการเข้าถึงอุปกรณ์
หากต้องการใช้อุปกรณ์หรือลักษณะเฉพาะบางประเภท เช่น Matter
OnOffTrait ที่ใช้ในตัวอย่างหลายรายการที่นี่ คุณต้องนำเข้าอุปกรณ์หรือลักษณะเฉพาะดังกล่าว โดยทำดังนี้
import GoogleHomeSDK
import GoogleHomeTypes
ตรวจสอบว่าลักษณะรองรับคำสั่งหรือไม่
ใช้ฟังก์ชัน supports ระดับลักษณะเพื่อตรวจสอบว่าอุปกรณ์หนึ่งๆ รองรับคำสั่งหรือไม่
ตัวอย่างเช่น หากต้องการตรวจสอบว่าอุปกรณ์รองรับคำสั่ง toggle ของลักษณะเปิด/ปิดหรือไม่ ให้ทำดังนี้
// 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") }
ส่งคำสั่งไปยังอุปกรณ์
การส่งคำสั่งจะคล้ายกับการอ่านแอตทริบิวต์สถานะจากลักษณะ หากต้องการเปิดหรือปิดอุปกรณ์ ให้ใช้คำสั่งสลับ 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 ของลักษณะเปิด/ปิดหรือไม่ ให้ทำดังนี้
// 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))" ) } } }
อัปเดตแอตทริบิวต์ลักษณะเฉพาะ
หากต้องการเปลี่ยนค่าของแอตทริบิวต์หนึ่งๆ และไม่มีคำสั่งใดของลักษณะที่ทำเช่นนั้น แอตทริบิวต์อาจรองรับการตั้งค่าอย่างชัดเจน
การเปลี่ยนแปลงค่าของแอตทริบิวต์ได้หรือไม่นั้นขึ้นอยู่กับปัจจัย 2 ประการดังนี้
- แอตทริบิวต์เขียนได้ไหม
- ค่าของแอตทริบิวต์จะเปลี่ยนแปลงได้ไหมเมื่อส่งคำสั่งลักษณะ
เอกสารอ้างอิงสำหรับลักษณะและแอตทริบิวต์จะมีข้อมูลนี้
ดังนั้นชุดค่าผสมของพร็อพเพอร์ตี้ที่กำหนดวิธีเปลี่ยนแปลงค่าของแอตทริบิวต์จึงมีดังนี้
อ่านอย่างเดียวและไม่ได้รับผลกระทบจากคำสั่งอื่นๆ ซึ่งหมายความว่าค่าของแอตทริบิวต์จะไม่เปลี่ยนแปลง เช่น แอตทริบิวต์
currentPositionของSwitchTraitอ่านอย่างเดียวและได้รับผลกระทบจากคำสั่งอื่นๆ ซึ่งหมายความว่าวิธีเดียวที่ค่าของแอตทริบิวต์จะเปลี่ยนแปลงได้คือการส่งคำสั่ง ตัวอย่างเช่น แอตทริบิวต์
currentLevelของLevelControlTraitเป็นแบบอ่านอย่างเดียว แต่ค่าของแอตทริบิวต์สามารถเปลี่ยนแปลงได้ด้วยคำสั่งต่างๆ เช่นmoveToLevelเขียนได้และไม่ได้รับผลกระทบจากคำสั่งอื่นๆ ซึ่งหมายความว่าคุณสามารถเปลี่ยนค่าของแอตทริบิวต์ได้โดยตรงโดยใช้ฟังก์ชัน
updateของลักษณะ แต่จะไม่มีคำสั่งที่ส่งผลต่อค่าของแอตทริบิวต์ เช่น แอตทริบิวต์WrongCodeEntryLimitของDoorLockTraitเขียนได้และได้รับผลกระทบจากคำสั่งอื่นๆ ซึ่งหมายความว่าคุณสามารถเปลี่ยนค่าของแอตทริบิวต์ได้โดยตรงโดยใช้ฟังก์ชัน
updateของลักษณะ และค่าของแอตทริบิวต์อาจเปลี่ยนแปลงได้จากการส่งคำสั่ง เช่น แอตทริบิวต์occupiedCoolingSetpointของThermostatTraitสามารถเขียนได้ แต่ก็อัปเดตด้วยคำสั่งsetpointRaiseLowerได้เช่นกัน
ตัวอย่างการใช้ฟังก์ชันอัปเดตเพื่อเปลี่ยนค่าของแอตทริบิวต์
ตัวอย่างนี้แสดงวิธีตั้งค่าแอตทริบิวต์ 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)
แอตทริบิวต์ลักษณะของส่วนประกอบกลุ่มและการจัดการข้อผิดพลาด
การกำหนดเป้าหมายส่วนของกลุ่มจะช่วยลดความซับซ้อนของกรณีทั่วไปที่คุณต้องการส่งคำสั่งแบบ Idempotent (เช่น การเปิดหรือปิดไฟ หรือการตั้งค่าระดับความสว่าง) ไปยังทั้งกลุ่ม เมื่อทำงานกับลักษณะและคำสั่งในส่วน DeviceGroup โปรดคำนึงถึงลักษณะการทำงานต่อไปนี้
- โดยทั่วไปแล้ว แอตทริบิวต์สถานะแบบไดนามิก (เช่น แอตทริบิวต์
onOffของOnOffTraitหรือแอตทริบิวต์currentLevelของLevelControlTrait) จะไม่แสดงในลักษณะของส่วนกลุ่ม เนื่องจากอุปกรณ์ที่เป็นสมาชิกในกลุ่มอาจอยู่ในสถานะที่แตกต่างกันซึ่งไม่สามารถรวมเป็นค่าเดียวได้ อย่างไรก็ตาม ระบบจะป้อนข้อมูลคำสั่งที่รองรับ (ตรวจสอบด้วยsupports(_:)เช่น.moveToLevelWithOnOffในหลอดไฟที่หรี่แสงได้) และแอตทริบิวต์ความสามารถบางอย่าง (เช่นcolorTempPhysicalMinMiredsและcolorTempPhysicalMaxMiredsในColorControlTraitสำหรับหลอดไฟสี) เพื่อให้แอปของคุณกำหนดค่าตัวควบคุม UI ได้อย่างเหมาะสม - คำสั่งบางรายการเกี่ยวกับลักษณะของสมาชิกกลุ่มอาจใช้ไม่ได้กับส่วนของกลุ่ม โดยเฉพาะอย่างยิ่ง คำสั่งที่แสดงผลค่าจะใช้ไม่ได้
- คำสั่งในส่วนของกลุ่มจะไม่แสดงผลลัพธ์แต่ละรายการสำหรับคำสั่งอุปกรณ์ของสมาชิกที่เกี่ยวข้องแต่ละรายการ หากต้องการตรวจสอบผลลัพธ์ของคำสั่งแต่ละรายการหรือเรียกใช้คำสั่งที่แสดงผลค่า ให้ทำซ้ำผ่านอุปกรณ์สมาชิกของกลุ่มโดยตรง
- คำสั่งที่ส่งไปยังส่วนหนึ่งใน
DeviceGroupจะเสร็จสมบูรณ์เมื่อการกระจายทั้งหมดในอุปกรณ์สมาชิกเสร็จสิ้น และระบบรวบรวมความสำเร็จหรือความล้มเหลวของคำสั่งที่เกี่ยวข้องทั้งหมดแล้ว คำสั่งจะดำเนินการไม่สำเร็จ (แสดงHomeError) ก็ต่อเมื่อคำสั่งดำเนินการไม่สำเร็จสำหรับอุปกรณ์สมาชิกที่เชื่อมโยงทุกเครื่อง หรือหากอุปกรณ์เป้าหมายทั้งหมดไม่พร้อมใช้งาน โดยจะแสดงเป็นคำสั่งเดียวที่ดำเนินการไม่สำเร็จซึ่งตรงกับไวยากรณ์การเรียกใช้คำสั่งเดียว หากอุปกรณ์สมาชิกอย่างน้อย 1 เครื่องดำเนินการตามคำสั่ง คำสั่งกลุ่มจะเสร็จสมบูรณ์โดยไม่แสดงข้อผิดพลาด
ส่งคำสั่งไปยังส่วนของกลุ่ม
วิธีเปิดไฟ 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: []
)
}