שליטה במכשירים

איך בודקים אם מאפיין תומך בפקודה

אפשר גם לבדוק אם יש תמיכה בפקודה של מאפיין. אפשר גם להשתמש בפונקציה supports ברמת המאפיין כדי לבדוק אם יש תמיכה בפקודה במכשיר מסוים.

לדוגמה, כדי לבדוק אם מכשיר תומך בפקודה toggle של המאפיין On/Off:

// Check if the OnOff trait supports the toggle command.
if (onOffTrait.supports(OnOff.Command.Toggle)) {
  println("onOffTrait supports toggle command")
} else {
  println("onOffTrait does not support stateful toggle command")
}

שליחת פקודה למכשיר

שליחת פקודה דומה לקריאת מאפיין מצב ממאפיין. כדי להפעיל או להשבית את המכשיר, משתמשים בפקודה Toggle של המאפיין OnOff, שמוגדר במודל הנתונים של הסביבה העסקית של Google Home בתור toggle(). השיטה הזו משנה את הערך של onOff ל-false אם הוא true, או ל-true אם הוא false:

// Calling a command on a trait.
try {
  onOffTrait.toggle()
} catch (e: HomeException) {
  // Code for handling the exception
}

כל הפקודות של המאפיינים הן פונקציות suspend, והן מסתיימות רק כשה-API מחזיר תשובה (למשל אישור שהמצב של המכשיר השתנה). אם תזוהה בעיה בתהליך הביצוע, הפקודות עשויות להחזיר חריגה. כמפתחים, כדאי להשתמש בבלוק try-catch כדי לטפל כראוי בחריגות האלה, ולהציג למשתמשים מידע מפורט במקרים שבהם אפשר לבצע פעולה כלשהי בעקבות השגיאות. חריגות שלא מטופלות יעצרו את סביבת זמן הריצה של האפליקציה, ויכול להיות שיגרמו לקריסות באפליקציה.

לחלופין, אפשר להשתמש בפקודות off() או on() כדי להגדיר את המצב במפורש:

onOffTrait.off()
onOffTrait.on()

אחרי שליחת הפקודה לשינוי המצב, כשהיא תושלם תוכלו לקרוא את המצב כפי שמתואר בקטע קריאת המצב של המכשיר כדי לטפל בו באפליקציה. לחלופין, תוכלו להשתמש בתהליכים כפי שמתואר בקטע מעקב אחרי המצב, שהיא השיטה המועדפת.

שליחת פקודה עם פרמטרים

בפקודות מסוימות יכולים להופיע פרמטרים, כמו אלה שמופיעים במאפיינים OnOff או LevelControl:

offWithEffect

// Turn off the light using the DyingLight effect.
onOffTrait.offWithEffect(
  effectIdentifier = OnOffTrait.EffectIdentifierEnum.DyingLight,
  effectVariant = 0u,
)

moveToLevel

// Change the brightness of the light to 50%
levelControlTrait.moveToLevel(
  level = 127u.toUByte(),
  transitionTime = null,
  optionsMask = LevelControlTrait.OptionsBitmap(),
  optionsOverride = LevelControlTrait.OptionsBitmap(),
)

לפקודות מסוימות יש ארגומנטים אופציונליים שמופיעים אחרי הארגומנטים הנדרשים.

לדוגמה, לפקודה step של המאפיין FanControl יש שני ארגומנטים אופציונליים:

val fanControlTraitFlow: Flow<FanControl?> =
  device.type(FanDevice).map { it.standardTraits.fanControl }.distinctUntilChanged()

val fanControl = fanControlTraitFlow.firstOrNull()

// Calling a command with optional parameters not set.
fanControl?.step(direction = FanControlTrait.StepDirectionEnum.Increase)

// Calling a command with optional parameters.
fanControl?.step(direction = FanControlTrait.StepDirectionEnum.Increase) { wrap = true }

איך בודקים אם מאפיין תומך במאפיין

יכול להיות שחלק מהמכשירים יתמכו במאפיין Matter, אבל לא במאפיין ספציפי. לדוגמה, יכול להיות שמכשיר Cloud-to-cloud שתואם ל-Matter לא תומך בכל המאפיינים של Matter. כדי לטפל במקרים כאלה, צריך להשתמש בפונקציה supports ברמת המאפיין וב-enum‏ Attribute של המאפיין כדי לבדוק אם יש תמיכה במאפיין במכשיר מסוים.

לדוגמה, כדי לבדוק אם מכשיר תומך במאפיין onOff של המאפיין'מופעל/מושבת':

// Check if the OnOff trait supports the onOff attribute.
if (onOffTrait.supports(OnOff.Attribute.onOff)) {
  println("onOffTrait supports onOff state")
} else {
  println("onOffTrait is for a command only device!")
}

חלק מהמאפיינים יכולים להיות ריקים במפרט Matter או בסכמה Cloud-to-cloud smart home. במאפיינים האלה, אפשר להשתמש ב-isNullable בנוסף ל-supports כדי לקבוע אם הערך null שהמאפיין מחזיר נובע מכך שהמכשיר לא מדווח על הערך הזה, או אם הערך של המאפיין הוא באמת null:

// Check if a nullable attribute is set or is not supported.
if (onOffTrait.supports(OnOff.Attribute.startUpOnOff)) {
  // The device supports startupOnOff, it is safe to expect this value in the trait.
  if (OnOff.Attribute.startUpOnOff.isNullable && onOffTrait.startUpOnOff == null) {
    // This value is nullable and set to null. Check the specification as to
    // what null in this case means
    println("onOffTrait supports startUpOnOff and it is null")
  } else {
    // This value is nullable and set to a value.
    println("onOffTrait supports startUpOnOff and it is set to ${onOffTrait.startUpOnOff}")
  }
} else {
  println("onOffTrait does not support startUpOnOff!")
}

עדכון מאפייני המאפיינים

אם אתם רוצים לשנות את הערך של מאפיין נתון ואף אחת מהפקודות של המאפיין לא עושה זאת, יכול להיות שהמאפיין תומך בהגדרת ערך מפורש.

האפשרות לשנות את הערך של מאפיין תלויה בשני גורמים:

  • האם אפשר לכתוב במאפיין?
  • האם הערך של המאפיין יכול להשתנות כתוצאה משליחת פקודה של מאפיין?

המידע הזה מופיע במסמכי העזרה לגבי המאפיינים והמאפיינים שלהם.

לכן, השילובים של המאפיינים שקובעים איך הערך של מאפיין יכול להשתנות הם:

  • לקריאה בלבד ולא מושפעת מפקודות אחרות. כלומר, הערך של המאפיין לא משתנה. לדוגמה, המאפיין currentPosition של המאפיין Switch.

  • לקריאה בלבד ומושפעת מפקודות אחרות. המשמעות היא שהדרך היחידה שבה הערך של המאפיין יכול להשתנות היא כתוצאה משליחת פקודה. לדוגמה, המאפיין currentLevel של המאפיין Matter של LevelControl הוא לקריאה בלבד, אבל אפשר לשנות את הערך שלו באמצעות פקודות כמו moveToLevel.

  • ניתן לכתוב בהן והן לא מושפעות מפקודות אחרות. כלומר, אפשר לשנות ישירות את הערך של המאפיין באמצעות הפונקציה update של המאפיין, אבל אין פקודות שמשפיעות על הערך של המאפיין. לדוגמה, המאפיין WrongCodeEntryLimit של המאפיין DoorLock.

  • ניתן לכתוב בהן והן מושפעות מפקודות אחרות. כלומר, אפשר לשנות את הערך של המאפיין ישירות באמצעות הפונקציה update של המאפיין, והערך של המאפיין יכול להשתנות כתוצאה משליחת פקודה. לדוגמה, אפשר לכתוב במאפיין occupiedCoolingSetpoint של המאפיין Thermostat, אבל אפשר גם לעדכן אותו באמצעות הפקודה setpointRaiseLower.

דוגמה לשימוש בפונקציית update כדי לשנות את הערך של מאפיין

בדוגמה הזו מוסבר איך להגדיר באופן מפורש את הערך של המאפיין DoorLockTrait.WrongCodeEntryLimit.

כדי להגדיר ערך למאפיין, קוראים לפונקציית update של המאפיין ומעבירים לה פונקציית מוטאטור שמגדירה את הערך החדש. מומלץ קודם לוודא שהמאפיין תומך במאפיין.

לדוגמה:

    var doorLockDevice = home.devices().list().first { device -> device.has(DoorLock) }

    val traitFlow: Flow<DoorLock?> =
      doorLockDevice.type(DoorLockDevice).map { it.standardTraits.doorLock }.distinctUntilChanged()

    val doorLockTrait: DoorLock = traitFlow.first()!!

    if (doorLockTrait.supports(DoorLock.Attribute.wrongCodeEntryLimit)) {
      val unused = doorLockTrait.update { setWrongCodeEntryLimit(3u) }
    }