מדריך ל-DSL ב-iOS

המדריך הבא יעזור לכם להבין איך אפשר להשתמש בצמתים שונים של Automation DSL כדי ליצור תהליך אוטומציה.

כל ה-DSL של האוטומציה ממוקם בצומת automation יחיד. הצומת automation יוצר את הגבול בין ההקשר החיצוני של שפת Swift לבין ההקשר המוטמע של ה-DSL.

תהליך עבודה ברצף

תהליך אוטומציה רצוף הוא סוג ברירת המחדל של תהליך אוטומציה.

דוגמה ל-DSL רצף

הנה תבנית בסיסית מאוד של Automation DSL שמשתמשת בתהליך רצוף שמורכב מגורם מפעיל, תנאי ופעולה:

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {
  starter(...)
  condition {...}
  action {...}
}

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

מתחילים

צמתים מעוררי תהליך מגדירים את הנסיבות הראשוניות שמפעילות תהליך אוטומציה. לדוגמה, שינוי במצב או בערך. תהליך אוטומציה חייב לכלול לפחות אירוע התחלה אחד, אחרת הוא לא יעמוד בתהליך האימות. כדי להוסיף יותר מ-starter אחד לפעולה אוטומטית, צריך להשתמש בצומת select.

תבנית ליצירת מודעות מבוססת על מאפיין של תכונה

כשמצהירים על צומת מתחיל שמבוסס על מאפיין של מאפיין, צריך לציין:

  • המכשיר
  • סוג המכשיר שאליו שייך המאפיין
  • המאפיין
starter(
  thermostat,
  Matter.TemperatureSensorDeviceType.self,
  Matter.TemperatureMeasurementTrait.self
)

הפרמטר device type נדרש כי הוא מאפשר לציין את סוג המכשיר שאליו מתייחסת האוטומציה. לדוגמה, מכשיר יכול להיות מורכב מ-FanDeviceType ומ-HeatingCoolingUnitDeviceType, ושניהם מכילים את המאפיין OnOffTrait. כשמציינים את סוג המכשיר, אין אי-בהירות לגבי החלק במכשיר שמפעיל את האוטומציה.

אירוע התחלה לפי אירוע

כשמגדירים צומת מתחיל שמבוסס על אירוע, צריך לציין:

  • המכשיר
  • סוג המכשיר שאליו שייך המאפיין
  • האירוע
starter(
  doorbell,
  Google.GoogleDoorbellDeviceType.self,
  Google.DoorbellPressTrait.DoorbellPressedEvent
)

ערכת התחלה שמבוססת על מבנה ואירוע, עם פרמטרים

לחלק מהאירועים יכולים להיות פרמטרים, ולכן צריך לכלול את הפרמטרים האלה גם ב-starter.

לדוגמה, ה-starter הזה משתמש ב-ScheduledEvent של TimeTrait כדי להפעיל את האוטומציה בשעה 7:00:

typealias TimeTrait = Google.TimeTrait

let earlyMorning = starter(
  structure,
  TimeTrait.ScheduledEvent.self
) {
  TimeTrait.ScheduledEvent.clockTime(TimeOfDay(hours: 7, minutes: 0))
}

מפעיל ידני

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

כשמגדירים מפעיל ידני:

  • אין לציין מאפיין או סוג מכשיר.
  • מספקים אלמנט בממשק המשתמש שמפעיל את Automation.execute().

כשמציבים התחלה ידנית בתהליך select יחד עם התחלה אחרת, ההתחלה הידנית מבטלת את ההתחלה האחרת:

select {
  manualStarter()
  starter(
    thermostat,
    Matter.TemperatureSensorDeviceType.self,
    Matter.TemperatureMeasurementTrait.self
  )
}

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

הפרדה בין התחלה ידנית לבין התחלה מותנית

אחת מהדרכים לבנות את האוטומציה כך שצמתים של condition לא יחסמו אוטומציה שהופעל באמצעות מפעיל ידני היא להציב את המפעיל השני בתהליך רצוף נפרד, יחד עם ה-condition שלו:

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

  select {
    sequential {
      starter(...)
      condition {...}
    }
    sequential {
      manualStarter()
    }
  }
  action {...}

}

הפניה לערך של מאפיין

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

עם stateReader:

typealias TimeTrait = Google.TimeTrait

let time = stateReader(structure, TimeTrait.self)
time
let currTime = time.currentTime

עם starter:

typealias LaundryWasherDeviceType = Matter.LaundryWasherDeviceType
typealias OnOffTrait = Google.OnOffTrait

let starterNode = starter(device1, LaundryWasherDeviceType.self, OnOffTrait.self)
starterNode
condition {
  starterNode.onOff.equals(true)
}

צמתים וביטויים של תנאים

צומת תנאי מייצג נקודת החלטה שקובעת אם האוטומציה תמשיך או לא. לתהליך אוטומציה יכולים להיות כמה צמתים מסוג condition. אם הביטוי של אחד מהצומתים מסוג condition מקבל את הערך false, הביצוע של כל האוטומציה מסתיים.

בצומת condition, אפשר לשלב כמה קריטריונים של תנאים באמצעות אופרטורים שונים, כל עוד הביטוי מקבל ערך בוליאני יחיד. אם הערך המתקבל הוא true, התנאי מתקיים והאוטומציה ממשיכה את הביצוע של הצומת הבא. אם הערך הוא false, האוטומציה תפסיק לפעול בנקודה הזו.

הביטויים נוצרים באופן דומה לביטויים ב-Swift, ויכולים להכיל ערכים פרימיטיביים כמו מספרים, תווים, מחרוזות וערכים בוליאניים, וגם ערכים של Enum. קיבוץ של ביטויים משניים בסוגריים מאפשר לכם לקבוע את הסדר שבו הם ייבדקו.

הנה דוגמה ל-condition שמשלב כמה ביטויים משניים לביטוי אחד:

condition {
  let exp1 = starterNode.lockState.equals(.unlocked)
  let exp2 = stateReaderNode.lockState.equals(true)
  let exp3 = occupancySensingDevice.occupied.notEquals(0)
  (exp1.and(exp2)).or(exp3)
}

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

typealias OnOffTrait = Matter.OnOffTrait

let starterNode = starter(device, OnOffTrait.self)
starterNode
condition {
  starterNode.onOff.equals(true)
}
val starterNode = starter<_>(device, OnOff)
condition() { expression = starterNode.onOff equals true }

stateReader

הדרך השנייה להפנות לערכים של מאפייני המאפיינים בצומת condition היא באמצעות צומת stateReader.

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

typealias ActivatedCarbonFilterMonitoringTrait = Matter.ActivatedCarbonFilterMonitoringTrait

let filterMonitoringState = stateReader(structure, ActivatedCarbonFilterMonitoringTrait.self)

לאחר מכן, מפנים ל-stateReader בצומת condition:

condition {
filterMonitoringState.changeIndication.equals(.warning)
}

באמצעות אופרטורים להשוואה ואופרטורים לוגיים, אפשר להשתמש במספר stateReaders בצומת condition:

typealias ArmDisarm = Google.ArmDisarmTrait
typealias DoorLockDevice = Matter.DoorLockDeviceType
typealias DoorLock = Matter.DoorLockTrait

let armState = stateReader(doorLock, DoorLockDevice.self, ArmDisarm )
let doorLockState = stateReader(doorLock, DoorLockDevice.self, DoorLock)
armState
doorLockState
condition {
  let exp1 = armState.armState
  let exp2 = doorLockState.lockState
  exp1.and(exp2)
}

משך התנאי

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

condition(for: .seconds(600)) {
lightStateReader.onOff.equals(true)
}

משך הזמן יכול לנוע בין דקה ל-30 דקות.

צמתים של פעולות

צומת הפעולה הוא המקום שבו מתבצעת העבודה של האוטומציה. בדוגמה הזו, הפעולה מפעילה את הפקודה AssistantBroadcastTrait's broadcast():

action(speaker, SpeakerDeviceType.self) {
  Google.AssistantBroadcastTrait.broadcast(msg: "Oven Cycle Complete")
}