Hướng dẫn về DSL Android

Hãy tham khảo hướng dẫn sau đây để tìm hiểu cách sử dụng nhiều nút DSL Tự động hoá để tạo một quy trình tự động hoá.

Tất cả DSL tự động hoá đều được đặt trong một nút automation duy nhất. Nút automation tạo thành ranh giới giữa ngữ cảnh ngôn ngữ Kotlin bên ngoài và ngữ cảnh DSL được nhúng.

Luồng tuần tự

Luồng tuần tự là loại luồng tự động hoá mặc định.

Ví dụ về DSL tuần tự

Sau đây là một mẫu DSL tự động hoá rất cơ bản, sử dụng một quy trình tuần tự bao gồm một trình khởi động, một điều kiện và một hành động:


import com.google.home.automation.action
import com.google.home.automation.automation
import com.google.home.automation.condition
import com.google.home.automation.sequential
import com.google.home.automation.starter

...

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

Bạn có thể tinh chỉnh bằng cách thêm các nút bổ sung.

Starter

Các nút khởi động xác định những trường hợp ban đầu kích hoạt một quy trình tự động hoá. Ví dụ: thay đổi về trạng thái hoặc giá trị. Một quy trình tự động hoá phải có ít nhất một điều kiện bắt đầu, nếu không, quy trình này sẽ không được xác thực. Để thêm nhiều điều kiện kích hoạt vào một quy trình tự động hoá, bạn phải sử dụng nút select.

Người bắt đầu dựa trên thuộc tính đặc điểm

Khi khai báo một nút khởi động dựa trên thuộc tính đặc điểm, hãy chỉ định:

  • thiết bị
  • loại thiết bị mà đặc điểm thuộc về
  • đặc điểm
starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)

Bạn phải dùng tham số loại thiết bị vì tham số này cho phép bạn chỉ định loại thiết bị mà quy trình tự động hoá sẽ xử lý trong một thiết bị. Ví dụ: một thiết bị có thể bao gồm FanDeviceHeatingCoolingUnitDevice, cả hai đều chứa đặc điểm OnOff. Bằng cách chỉ định loại thiết bị, bạn sẽ không bị nhầm lẫn về bộ phận nào của thiết bị kích hoạt quy trình tự động hoá.

Starter dựa trên sự kiện

Khi khai báo một nút khởi động dựa trên một sự kiện, hãy chỉ định:

  • thiết bị
  • loại thiết bị mà đặc điểm thuộc về
  • sự kiện
starter<_>(doorBell, GoogleDoorbellDevice, DoorbellPressed)

Mẫu dựa trên cấu trúc và sự kiện, có thông số

Một số sự kiện có thể có các thông số, vì vậy bạn cũng cần phải thêm các thông số này vào trình khởi chạy.

Ví dụ: chế độ cài đặt này sử dụng ScheduledTimeEvent của đặc điểm Time để kích hoạt chế độ tự động hoá lúc 7:00:

val earlyMorning = starter<_>(structure, Time.ScheduledTimeEvent) {
  parameter(Time.ScheduledTimeEvent.clockTime(
    LocalTime.of(7, 0, 0, 0)))
}

Bộ khởi động thủ công

Trình kích hoạt thủ công là một loại trình kích hoạt đặc biệt cho phép người dùng chạy quy trình tự động hoá theo cách thủ công.

Khi khai báo một trình khởi chạy thủ công:

  • Đừng chỉ định một đặc điểm hoặc loại thiết bị.
  • Cung cấp một phần tử trên giao diện người dùng gọi Automation.execute().

Khi bạn đặt một điều kiện khởi động thủ công trong một luồng select cùng với một điều kiện khởi động khác, điều kiện khởi động thủ công sẽ ghi đè điều kiện khởi động kia:

select {
  manualStarter()
  starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)
}

Xin lưu ý rằng mọi nút condition theo sau một nút khởi động thủ công sẽ được đánh giá và có thể chặn quá trình thực thi tự động hoá, tuỳ thuộc vào biểu thức condition.

Tách bộ khởi động thủ công khỏi bộ khởi động có điều kiện

Một cách để cấu trúc quy trình tự động hoá sao cho các nút condition không chặn quy trình tự động hoá được kích hoạt bằng một bộ khởi động thủ công là đặt bộ khởi động khác trong một quy trình tuần tự riêng biệt cùng với condition:

automation_graph {
  sequential {
    select {
      sequential {
        starter<_>(...)
        condition {...}
      }
      sequential {
        manualStarter()
      }
    }
    action {...}
  }
}

Tham chiếu giá trị của một thuộc tính

Để sử dụng giá trị của một thuộc tính trong biểu thức, hãy sử dụng cú pháp sau.

Với stateReader:

val time = stateReader<_>(structure, Structure, Time)
val currTime = time.currentTime

Với starter:

val starterNode = starter<_>(device1, LaundryWasherDevice, OnOff)
condition() {
  expression = starterNode.onOff equals true
}

Biểu thức và nút điều kiện

Nút điều kiện đại diện cho một điểm quyết định để xác định xem quy trình tự động hoá có tiếp tục hay không. Một quy trình tự động hoá có thể có nhiều nút condition. Nếu biểu thức của bất kỳ nút condition nào đánh giá thành false, thì quá trình thực thi toàn bộ quy trình tự động hoá sẽ kết thúc.

Trong một nút condition, bạn có thể kết hợp nhiều tiêu chí điều kiện bằng cách sử dụng nhiều toán tử, miễn là biểu thức đánh giá thành một giá trị boolean duy nhất. Nếu giá trị nhận được là true, thì điều kiện được đáp ứng và quy trình tự động hoá sẽ tiếp tục thực thi nút tiếp theo. Nếu là false, quá trình tự động hoá sẽ dừng thực thi tại thời điểm đó.

Các biểu thức được hình thành tương tự như các biểu thức trong Kotlin và có thể chứa các giá trị nguyên thuỷ như số, ký tự, chuỗi và boolean, cũng như các giá trị Enum. Việc nhóm các biểu thức phụ bằng dấu ngoặc đơn giúp bạn kiểm soát thứ tự đánh giá các biểu thức đó.

Dưới đây là ví dụ về condition kết hợp nhiều biểu thức con thành một biểu thức duy nhất:

condition() {
  val expr1 = starterNode.lockState equals DlLockState.Unlocked
  val expr2 = stateReaderNode.lockState equals true

  val expr3 = occupancySensingDevice.occupied notEquals 0
  val expr4 = timeStateReaderNode
    .currentTime
    .between(
      timeStateReaderNode.sunsetTime,
      timeStateReaderNode.sunriseTime)
  expression = (expr1 and expr2) or (expr3 and expr4)
}

Bạn có thể tham chiếu giá trị của một đặc điểm được truy cập thông qua một thành phần khởi động:

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

stateReader

Cách khác để tham chiếu các giá trị thuộc tính đặc điểm trong một nút condition là dùng nút stateReader.

Để làm việc này, trước tiên, hãy ghi lại giá trị thuộc tính đặc điểm trong một nút stateReader. stateReader lấy structure và đặc điểm làm đối số:

import com.google.home.automation.stateReader
...
val filterMonitoringState = stateReader<_>(structure, ActivatedCarbonFilterMonitoring)

Sau đó, hãy tham chiếu stateReader trong nút condition:

condition() {
  expression =
    filterMonitoringState.changeIndication
      .equals(ChangeIndicationEnum.Warning)
}

Bằng cách sử dụng phép so sánhtoán tử logic, bạn có thể dùng nhiều stateReaders trong một nút condition:

val armState = stateReader<_>(doorLock, DoorLockDevice, ArmDisarm )
val doorLockState = stateReader<_>(doorLock, DoorLockDevice, DoorLock)
condition() {
  expression =
    (armState.armState equals true)
    and
    (doorLockState.lockState equals true)
}

Thời lượng của điều kiện

Ngoài biểu thức boolean trong một điều kiện, bạn có thể chỉ định một khung thời gian mà biểu thức phải đúng để chạy thao tác tự động. Ví dụ: bạn có thể xác định một điều kiện chỉ kích hoạt nếu đèn đã bật trong 10 phút.

  condition {
    expression(lightStateReader.onOff == true)
    forDuration(Duration.ofMinutes(10))
  }

Thời lượng có thể từ 1 đến 30 phút.

Nút hành động

Nút hành động là nơi diễn ra hoạt động của quy trình tự động hoá. Trong ví dụ này, thao tác sẽ gọi lệnh broadcast() của đặc điểm AssistantBroadcast:

action(device, SpeakerDevice) {
  command(AssistantBroadcast.broadcast("Intruder detected!"))
}

Câu lệnh nhập

Khi phát triển các quy trình tự động hoá, không phải lúc nào bạn cũng biết cách nhập nhiều phần tử của Home API vào mã của mình.

Các thuộc tính đặc điểm được nhập từ đối tượng Companion của đặc điểm:

import com.google.home.matter.standard.OnOff.Companion.onOff

Các cấu trúc dữ liệu do đặc điểm xác định được nhập từ lớp đặc điểm có tên kết thúc bằng "-Trait":

import com.google.home.matter.standard.MediaPlaybackTrait.PlaybackStateEnum

Các lệnh đặc điểm được nhập từ đối tượng Companion của đặc điểm:

import com.google.home.matter.standard.Thermostat.Companion.setTemperatureSetpointHold