מדריך ל-Android DSL לפעולות אוטומציה מורכבות

אפשר להשתמש ב-DSL של האוטומציה כדי ליצור אוטומציות מורכבות יותר מאלה שמתוארות במדריך ל-DSL – אוטומציות בסיסיות ב-Android.

רצף עם כמה פעולות

רצף עם כמה פעולות

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

automation {
  sequential {
    starter<_>(...)
    condition {...}
    action {...}
    action {...}
    action {...}
    }
}

רצף עם כמה פעולות במקביל

רצף עם כמה פעולות במקביל

אם ממקמים כמה צומתי action בצומת parallel, הפעולות מתבצעות בו-זמנית.

automation {
  sequential {
    starter<_>(...)
    condition {...}
    parallel {
      action {...}
      action {...}
      action {...}
    }
  }
}

אם יש צמתים מסוג action בצומת sequential שמופיעים אחרי הצומת parallel, הם ימתינו עד שכל הצמתים בצומת parallel יסיימו לפעול.

הרצה מותנית

כברירת מחדל, פעולה אוטומטית מפעילה צמתים ברצף או במקביל. אם אתם צריכים לוגיקה של הסתעפות מותנית – ביצוע פעולות או נתיבים שונים על סמך תנאים בזמן הריצה – השתמשו בהצהרות if-then-else, שנוצרות באמצעות בלוקים של DSL של זרימת בקרה מותנית: ifThen, elseIf, ו- orElse.

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

  • צומת condition: מפסיק את ההפעלה של כל תהליך האוטומציה (או של נתיב ההפעלה הנוכחי) אם הביטוי הוא false.
  • ‫ifThen / elseIf / orElse: הערכת התנאים לפי הסדר. אם התנאי הוא false, הביצוע עובר לענף הבא של elseIf, לענף החלופי של orElse, או ממשיך לצמתים הבאים באוטומציה אם אף תנאי לא מתקיים.

ביצוע פעולה על סמך תנאי

הבלוק ifThen מעריך ביטוי מותנה. אם הביטוי מקבל את הערך true, הפעולות או הצמתים של DSL שמוטמעים בתוך הבלוק מופעלים. אם הערך הוא false, המערכת מדלגת על הפעולות והאוטומציה ממשיכה לצמתים הבאים בתהליך הרציף.

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

// When a door opens, turn on the light only if it is off,
// and always broadcast an announcement.
automation {
  sequential {
    val contactState = starter<_>(
      contactSensor,
      ContactSensorDevice,
      BooleanState,
    )
    val lightState = stateReader<_>(
      light,
      DimmableLightDevice,
      OnOff,
    )

    condition {
      // Door opened (contact sensor open)
      expression = contactState.stateValue equals false
    }

    // Conditionally turn on the light if it's off
    ifThen(lightState.onOff equals false) {
      action(light, DimmableLightDevice) { command(OnOff.on()) }
    }

    // Continue executing subsequent actions in the sequential flow
    action(structure) {
      command(AssistantBroadcast.broadcast("The door was opened."))
    }
  }
}

ביצוע פעולות שונות על סמך תנאי

כדי לבצע קבוצה אחת של פעולות כשהתנאי נכון וקבוצה אחרת של פעולות כשהתנאי לא נכון, צריך לשרשר את הבלוק האופציונלי .orElse { ... } אחרי ifThen(...) { ... }:

// When the door is unlocked, turn on the entryway light if it is off;
// otherwise, broadcast a welcome message.
automation {
  sequential {
    val doorLockEvent = starter<_>(
      doorLock,
      DoorLockDevice,
      LockOperationEvent,
    )
    val lightState = stateReader<_>(
      light,
      DimmableLightDevice,
      OnOff,
    )

    condition {
      expression =
        doorLockEvent.lockOperationType equals LockOperationTypeEnum.Unlock
    }

    ifThen(lightState.onOff equals false) {
      action(light, DimmableLightDevice) { command(OnOff.on()) }
    }.orElse {
      action(structure) {
        command(AssistantBroadcast.broadcast("Welcome home!"))
      }
    }
  }
}

שרשור של כמה תנאים ברצף

אפשר לשרשר בלוק אחד או יותר של .elseIf(...) { ... } כדי להעריך כמה תנאים ברצף. הענף הראשון שהתנאי שלו מקבל ערך true מופעל, וכל שאר הענפים נדלגים. אם אף אחד מהתנאים לא מקבל את הערך true, מופעל בלוק .orElse { ... } אופציונלי (אם הוא קיים):

// Adjust climate controls based on room temperature changes.
automation {
  sequential {
    val tempStarter = starter<_>(
      tempSensor,
      TemperatureSensorDevice,
      TemperatureMeasurement,
    )

    // If temperature is high (>= 28°C / 2800 mC), switch thermostat to Cool mode
    ifThen(tempStarter.measuredValue greaterThanOrEquals 2800) {
      action(thermostat, ThermostatDevice) {
        command(
          SimplifiedThermostat.setSystemMode(
            SimplifiedThermostatSystemModeEnum.Cool
          )
        )
      }
    }.elseIf(tempStarter.measuredValue lessThan 1800) {
      // If temperature is low (< 18°C / 1800 mC), switch to Heat mode
      action(thermostat, ThermostatDevice) {
        command(
          SimplifiedThermostat.setSystemMode(
            SimplifiedThermostatSystemModeEnum.Heat
          )
        )
      }
    }.orElse {
      // Otherwise, turn on the fan
      action(fan, FanDevice) {
        command(OnOff.on())
      }
    }
  }
}

תהליכים מותנים בתוך תהליכים מותנים

אפשר להוסיף בלוקים מותנים בתוך בלוקים אחרים של ifThen,‏ elseIf או orElse, וגם לשלב אותם עם צמתים של parallel,‏ delayFor ו-stateReader.

הבלוקים ifThen,‏ elseIf ו-orElse מריצים את התוכן שלהם כרצפים עוקבים. אתם יכולים להציב כל צומת רציף בתוך כל ענף, כולל בלוקים של action, stateReader, parallel, delayFor ו-ifThen בתצוגת עץ.

עיכובים

אפשר להוסיף השהיות לאוטומציות באמצעות מילת המפתח delayFor, שמקבלת ארגומנט java.time.Duration שמייצג את משך ההשהיה לפני המשך הביצוע. משך ההשהיה יכול להיות בין 5 שניות ל-24 שעות.

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

sequential {
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
  delayFor(Duration.ofSeconds(5))
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
  delayFor(Duration.ofSeconds(5))
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
  delayFor(Duration.ofSeconds(5))
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
}

הפעלת החרגה

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

כדי להחיל השהיית טריגרים על האוטומציה, משתמשים במילת המפתח suppressFor עם הארגומנט java.time.Duration שמייצג את משך ההמתנה לפני תגובה לטריגרים הבאים. משך ההשתקה יכול להיות קצר (חמש שניות) או ארוך (24 שעות).

automation {
  sequential {
    val starterNode = starter<_>(device, OccupancySensor, MotionDetection)
    suppressFor(Duration.ofMinutes(30))
    action(light, OnOffLightDevice) { command(OnOff.toggle()) }
}

חשוב לזכור שביטול הטריגר משפיע על כל starters באוטומציה שמופיעים לפני suppressFor.

הגבלת מספר ההרצות

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

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

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

automation {
  // The automation can only be executed once.
  maxExecutionCount = 1
  // When the door lock state changes
  sequential {
    val doorLockEvent = starter<_>(doorLock, DoorLockDevice, LockOperationEvent)
    // if the door is unlocked
    condition() {
      expression = (doorLockEvent.lockOperationType equals LockOperationTypeEnum.Unlock)
    }
    // turn the light on
    action(light, DimmableLightDevice) { command(OnOff.on()) }
  }
}

הפעולה האוטומטית נמחקת מיד אחרי שהיא מסתיימת בפעם האחרונה ומגיעה ל-maxExecutionCount. הרשומה של האוטומציה בהיסטוריה נשארת בכרטיסייה פעילות של Google Home app (GHA), כולל automation_id.

הגדרת מאפייני תכונות בפעולה

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

  1. יוצרים צומת update בתוך צומת action, וכוללים את המאפיין הרלוונטי כארגומנט לצומת update:
    action(deviceReference, deviceType) {
      update(trait) {
    
      }
    }
  2. בצומת update, לכל מאפיין שרוצים לשנות, משתמשים בפונקציית מוטציה ומעבירים לה את הערך החדש. כדי ליצור את השם של פונקציית המוטציה:
    1. השתמשו באותיות רישיות בשם המאפיין
    2. מוסיפים את המילה set בתחילת השם.
    לדוגמה, כדי לעדכן מאפיין שנקרא defaultMoveRate, צריך להשתמש בפונקציית מוטציה שנקראת setDefaultMoveRate.

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

action(device, Fan) {
  update(FanControl) {
    setPercentSetting(50u)
    setRockSetting(FanControlCluster.RockBitmap.rockUpDown)
  }
}