מדריך ל-DSL ב-iOS

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

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

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

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

דוגמה ל-DSL רציף

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

import GoogleHomeSDK
import GoogleHomeTypes

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

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

מתחילים

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

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

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

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

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

גורם מפעיל שמבוסס על אירוע

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

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

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

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

לדוגמה, הגורם הבא משתמש בScheduledEvent של TimeTrait כדי להפעיל את הפעולה האוטומטית בשעה 7:00:

typealias TimeTrait = Google.TimeTrait

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

גורם התחלה שמבוסס על מזג האוויר

אתם יכולים לציין תנאי מזג אוויר נוכחיים או חזויים בגורם להפעלה, באמצעות התכונה "מזג אוויר":

let weatherState = starter<_>(structure, trait = Weather)

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

הפעלה ידנית

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

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

  • אל תציינו תכונה או סוג מכשיר.
  • מוסיפים רכיב בממשק המשתמש שמפעיל את 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 דקות.

צומתי פעולה

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

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