Panduan DSL iOS untuk otomatisasi yang kompleks

DSL Otomatisasi dapat digunakan untuk membuat otomatisasi yang lebih kompleks daripada yang dibahas dalam Panduan DSL - otomatisasi dasar di iOS.

Berurutan dengan beberapa tindakan

Berurutan dengan beberapa tindakan

Otomatisasi dapat melakukan lebih dari satu hal. Misalnya, sebagai pengganti node action tunggal, Anda dapat memiliki beberapa node action, yang berjalan dalam urutan berurutan:

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

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

}

Berurutan dengan beberapa tindakan paralel

Berurutan dengan beberapa tindakan paralel

Jika Anda menempatkan beberapa node action dalam node parallel, tindakan akan dieksekusi secara bersamaan.

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

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

}

Jika ada action node dalam node sequential yang muncul setelah node parallel, node tersebut akan menunggu untuk dieksekusi hingga semua node dalam node parallel selesai dieksekusi.

Eksekusi bersyarat

Secara default, otomatisasi menjalankan node secara berurutan atau paralel. Jika Anda memerlukan logika percabangan bersyarat—mengeksekusi tindakan atau jalur yang berbeda berdasarkan kondisi runtime—gunakan pernyataan if-then-else, yang dibuat menggunakan blok DSL alur kontrol bersyarat: ifThen, elseIf, dan orElse.

Meskipun node condition standar membatasi seluruh otomatisasi (jika kondisi dievaluasi menjadi false, eksekusi otomatisasi akan segera dihentikan), blok ifThen memungkinkan alur kontrol percabangan:

  • Node condition: Menghentikan eksekusi seluruh otomatisasi (atau jalur eksekusi saat ini) jika ekspresinya adalah false.
  • ifThen / elseIf / orElse: Mengevaluasi kondisi secara berurutan. Jika kondisinya false, eksekusi akan berlanjut ke cabang elseIf berikutnya, cabang penggantian orElse, atau berlanjut ke node berikutnya dalam otomatisasi jika tidak ada kondisi yang terpenuhi.

Menjalankan tindakan berdasarkan kondisi

Blok ifThen mengevaluasi ekspresi kondisional. Jika ekspresi dievaluasi sebagai true, tindakan atau node DSL yang berada di dalam blok akan dieksekusi. Jika dievaluasi menjadi false, tindakan akan dilewati, dan otomatisasi akan dilanjutkan ke node berikutnya dalam alur berurutan.

Anda dapat menggunakan blok ifThen mandiri jika hanya ingin melakukan tindakan secara kondisional tanpa memblokir atau menghentikan node berikutnya dalam otomatisasi:

// When a door opens, turn on the light only if it is off,
// and always broadcast an announcement.
typealias ContactSensorDevice = Matter.ContactSensorDeviceType
typealias BooleanStateTrait = Matter.BooleanStateTrait
typealias DimmableLightDevice = Matter.DimmableLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let contactState = starter(
    contactSensor,
    ContactSensorDevice.self,
    BooleanStateTrait.self
  )
  let lightState = stateReader(
    light,
    DimmableLightDevice.self,
    OnOffTrait.self
  )
  contactState
  lightState

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

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

  // Continue executing subsequent actions in the sequential flow
  action(structure) {
    Google.AssistantBroadcastTrait.broadcast(msg: "The door was opened.")
  }
}

Mengeksekusi tindakan yang berbeda berdasarkan kondisi

Untuk menjalankan satu set tindakan saat kondisi benar dan set tindakan alternatif saat kondisi salah, gabungkan blok .orElse { ... } opsional setelah ifThen(...) { ... }:

// When the door is unlocked, turn on the entryway light if it is off;
// otherwise, broadcast a welcome message.
typealias DoorLockDevice = Matter.DoorLockDeviceType
typealias DoorLockTrait = Matter.DoorLockTrait
typealias DimmableLightDevice = Matter.DimmableLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let doorLockEvent = starter(
    doorLock,
    DoorLockDevice.self,
    DoorLockTrait.LockOperationEvent.self
  )
  let lightState = stateReader(
    light,
    DimmableLightDevice.self,
    OnOffTrait.self
  )
  doorLockEvent
  lightState

  condition {
    doorLockEvent.lockOperationType.equals(.unlock)
  }

  ifThen(lightState.onOff.equals(false)) {
    action(light, DimmableLightDevice.self) {
      OnOffTrait.on()
    }
  }.orElse {
    action(structure) {
      Google.AssistantBroadcastTrait.broadcast(msg: "Welcome home!")
    }
  }
}

Merangkai beberapa kondisi secara berurutan

Anda dapat menggabungkan satu atau beberapa blok .elseIf(...) { ... } opsional untuk mengevaluasi beberapa kondisi secara berurutan. Cabang pertama yang kondisinya bernilai true akan dieksekusi, dan semua cabang yang tersisa akan dilewati. Jika tidak ada kondisi yang bernilai true, blok .orElse { ... } opsional akan dieksekusi (jika diberikan):

// Adjust climate controls based on room temperature changes.
typealias TemperatureSensorDeviceType = Matter.TemperatureSensorDeviceType
typealias TemperatureMeasurementTrait = Matter.TemperatureMeasurementTrait
typealias ThermostatDeviceType = Matter.ThermostatDeviceType
typealias SimplifiedThermostatTrait = Google.SimplifiedThermostatTrait
typealias FanDeviceType = Matter.FanDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let tempStarter = starter(
    tempSensor,
    TemperatureSensorDeviceType.self,
    TemperatureMeasurementTrait.self
  )
  tempStarter

  // If temperature is high (>= 28°C / 2800 mC), switch thermostat to Cool mode
  ifThen(tempStarter.measuredValue.greaterThanOrEquals(2800)) {
    action(thermostat, ThermostatDeviceType.self) {
      SimplifiedThermostatTrait.setSystemMode(systemMode: .cool)
    }
  }.elseIf(tempStarter.measuredValue.lessThan(1800)) {
    // If temperature is low (< 18°C / 1800 mC), switch to Heat mode
    action(thermostat, ThermostatDeviceType.self) {
      SimplifiedThermostatTrait.setSystemMode(systemMode: .heat)
    }
  }.orElse {
    // Otherwise, turn on the fan
    action(fan, FanDeviceType.self) {
      OnOffTrait.on()
    }
  }
}

Alur bersyarat bertingkat

Blok bersyarat dapat disarangkan di dalam blok ifThen, elseIf, atau orElse lainnya, serta digabungkan dengan node parallel, delay(for:), dan stateReader.

Blok ifThen, elseIf, dan orElse menjalankan isinya sebagai alur berurutan. Anda dapat menempatkan node berurutan di dalam setiap cabang, termasuk action, stateReader, parallel, delay(for:), dan blok ifThen bertingkat.

Keterlambatan

Anda dapat memperkenalkan jeda dalam otomatisasi menggunakan metode delay(for:), yang menggunakan argumen Duration yang menunjukkan berapa lama jeda sebelum melanjutkan eksekusi. Durasi jeda dapat sesingkat lima detik atau selama 24 jam.

Misalnya, untuk mengalihkan lampu empat kali dengan jeda lima detik di antara setiap pengalihan:

typealias OnOffLightDevice = Matter.OnOffLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

sequential {
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
}

Pencegahan pemicu

Penekanan pemicu adalah kemampuan yang memungkinkan otomatisasi Anda mengabaikan starter selama jangka waktu tertentu setelah peristiwa pemicu awal. Mis alnya, jika otomatisasi memiliki starter yang dipicu oleh deteksi gerakan, dan jika Anda menentukan durasi penekanan pemicu selama lima menit, maka saat starter dipicu, tidak akan dipicu lagi selama lima menit berikutnya. Hal ini mencegah otomatisasi dipicu berulang kali dengan cepat.

Untuk menerapkan penekanan pemicu ke otomatisasi, gunakan kata kunci suppress(for:) dengan argumen Duration yang mewakili durasi waktu tunggu sebelum merespons pemicu berikutnya. Durasi penekanan dapat sesingkat lima detik atau selama 24 jam.

typealias OccupancySensorDevice = Matter.OccupancySensorDeviceType
typealias OnOffLightDevice = Matter.OnOffLightDeviceType
typealias MotionDetectionTrait = Google.MotionDetectionTrait
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let starterNode = starter(device, OccupancySensorDevice.self, MotionDetectionTrait.self)
  starterNode
  suppress(for: .seconds(30 * 60)) // 30 minutes
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
}

Perhatikan bahwa penekanan pemicu memengaruhi semua starters dalam otomatisasi yang mendahului Suppression.

Membatasi jumlah eksekusi

Anda dapat membatasi jumlah waktu yang diizinkan untuk menjalankan otomatisasi.

Misalnya, Anda mungkin ingin menyiapkan otomatisasi sekali jalan yang menjalankan penyedot debu saat Anda tidak berada di rumah selama seharian.

Untuk melakukannya, tetapkan kolom metadata maxExecutionCount otomatisasi. Contoh berikut adalah otomatisasi yang hanya dapat dieksekusi satu kali:

import GoogleHomeSDK
import GoogleHomeTypes

typealias RoboticVacuumCleanerDevice = Matter.RoboticVacuumCleanerDeviceType
typealias RvcRunModeTrait = Matter.RvcRunModeTrait
typealias AreaPresenceStateTrait = Google.AreaPresenceStateTrait

let draftAutomation = automation(
  name: "Vacuum home away",
  description: "Run the vacuum once when everyone is away.",
  maxExecutionCount: 1
) {
  let homeAwayState = starter(structure, AreaPresenceStateTrait.self)
  homeAwayState

  condition {
    homeAwayState.presenceState.equals(.presenceStateVacant)
  }

  action(vacuum, RoboticVacuumCleanerDevice.self) {
    RvcRunModeTrait.changeToMode(newMode: 1)
  }
}

Otomatisasi akan langsung dihapus setelah selesai dieksekusi untuk terakhir kalinya dan maxExecutionCount tercapai. Entri histori otomatisasi tetap ada di tab Google Home app (GHA) Aktivitas, termasuk automation_id.

Menetapkan atribut sifat dalam tindakan

Untuk menetapkan nilai atribut karakteristik:

  1. Buat node update dalam node action, termasuk sifat yang relevan sebagai argumen ke node update:
    action(deviceReference, deviceType) {
      update(trait) {
    
      }
    }
    
  2. Dalam node update, untuk setiap atribut yang akan diubah, gunakan fungsi mutator, dan teruskan nilai baru. Untuk membentuk nama fungsi mutator:
    1. Menggunakan huruf kapital pada nama atribut
    2. Awali dengan kata set.
    Misalnya, untuk memperbarui atribut yang disebut defaultMoveRate, Anda akan menggunakan fungsi mutator yang disebut setDefaultMoveRate.

Perhatikan bahwa node update dapat memiliki beberapa fungsi mutator. Berikut contoh saat dua atribut diperbarui:

typealias FanDeviceType = Matter.FanDeviceType
typealias FanControlTrait = Matter.FanControlTrait

action(fan, FanDeviceType.self) {
  update(FanControlTrait.self) {
    $0.setFanMode(.on)
  }
}