Hướng dẫn về DSL Android cho các quy trình tự động hoá phức tạp

Bạn có thể dùng DSL tự động hoá để tạo các quy trình tự động hoá phức tạp hơn so với những quy trình được thảo luận trong Hướng dẫn về DSL – quy trình tự động hoá cơ bản trên Android.

Tuần tự với nhiều hành động

Tuần tự với nhiều hành động

Một quy trình tự động có thể thực hiện nhiều việc. Ví dụ: thay vì một nút action, bạn có thể có nhiều nút action chạy theo thứ tự tuần tự:

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

Tuần tự với nhiều hành động song song

Tuần tự với nhiều hành động song song

Nếu bạn đặt nhiều nút action trong một nút parallel, thì các hành động sẽ thực thi đồng thời.

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

Nếu có các nút action trong nút sequential xuất hiện sau nút parallel, thì các nút đó sẽ đợi cho đến khi tất cả các nút trong nút parallel thực thi xong.

Thực thi có điều kiện

Theo mặc định, một quy trình tự động hoá sẽ thực thi các nút theo tuần tự hoặc song song. Nếu bạn cần logic phân nhánh có điều kiện (thực thi các hành động hoặc đường dẫn khác nhau dựa trên điều kiện thời gian chạy), hãy sử dụng câu lệnh if-then-else, được tạo bằng các khối DSL luồng điều khiển có điều kiện: ifThen, elseIf và orElse.

Mặc dù nút condition tiêu chuẩn kiểm soát toàn bộ quy trình tự động hoá (nếu điều kiện được đánh giá là false, thì quy trình tự động hoá sẽ chấm dứt thực thi ngay lập tức), nhưng các khối ifThen cho phép phân nhánh luồng điều khiển:

  • condition node: Dừng thực thi toàn bộ quy trình tự động hoá (hoặc đường dẫn thực thi hiện tại) nếu biểu thức là false.
  • ifThen / elseIf / orElse: Đánh giá các điều kiện theo thứ tự. Nếu một điều kiện là false, thì quá trình thực thi sẽ chuyển sang nhánh elseIf tiếp theo, nhánh dự phòng orElse hoặc tiếp tục đến các nút tiếp theo trong quy trình tự động hoá nếu không có điều kiện nào được đáp ứng.

Thực hiện một hành động dựa trên một điều kiện

Khối ifThen đánh giá một biểu thức có điều kiện. Nếu biểu thức cho kết quả là true, thì các hành động hoặc nút DSL lồng trong khối sẽ được thực thi. Nếu điều kiện được đánh giá là false, thì các hành động sẽ bị bỏ qua và quy trình tự động hoá sẽ tiếp tục đến các nút tiếp theo trong quy trình tuần tự.

Bạn có thể sử dụng một khối ifThen độc lập khi chỉ muốn thực hiện một hành động có điều kiện mà không chặn hoặc chấm dứt các nút tiếp theo trong quy trình tự động hoá:

// 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."))
    }
  }
}

Thực hiện các hành động khác nhau dựa trên một điều kiện

Để thực thi một tập hợp hành động khi điều kiện là đúng và một tập hợp hành động thay thế khi điều kiện là sai, hãy liên kết khối .orElse { ... } không bắt buộc sau 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!"))
      }
    }
  }
}

Kết hợp nhiều điều kiện theo trình tự

Bạn có thể liên kết một hoặc nhiều khối .elseIf(...) { ... } không bắt buộc để đánh giá nhiều điều kiện theo trình tự. Nhánh đầu tiên có điều kiện được đánh giá là true sẽ được thực thi và tất cả các nhánh còn lại sẽ bị bỏ qua. Nếu không có điều kiện nào được đánh giá là true, thì một khối .orElse { ... } không bắt buộc sẽ thực thi (nếu được cung cấp):

// 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())
      }
    }
  }
}

Luồng có điều kiện lồng nhau

Bạn có thể lồng các khối có điều kiện vào bên trong các khối ifThen, elseIf hoặc orElse khác, cũng như kết hợp với các nút parallel, delayFor và stateReader.

Các khối ifThen, elseIf và orElse thực thi nội dung của chúng dưới dạng luồng tuần tự. Bạn có thể đặt bất kỳ nút tuần tự nào bên trong mỗi nhánh, bao gồm cả các khối action, stateReader, parallel, delayFor và ifThen lồng nhau.

Chậm trễ

Bạn có thể thêm khoảng tạm dừng vào quy trình tự động hoá bằng từ khoá delayFor. Từ khoá này nhận đối số java.time.Duration thể hiện thời gian tạm dừng trước khi tiếp tục thực thi. Thời lượng tạm dừng có thể ngắn nhất là 5 giây hoặc dài nhất là 24 giờ.

Ví dụ: để bật/tắt đèn 4 lần, mỗi lần cách nhau 5 giây:

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()) }
}

Ngăn chặn điều kiện kích hoạt

Tính năng chặn điều kiện kích hoạt cho phép quy trình tự động hoá bỏ qua một starter trong một khoảng thời gian nhất định sau sự kiện kích hoạt ban đầu. Ví dụ: nếu quy trình tự động hoá có một starter được kích hoạt bằng tính năng phát hiện chuyển động và nếu bạn chỉ định thời gian chặn trình kích hoạt là 5 phút, thì khi starter kích hoạt, quy trình này sẽ không kích hoạt lại trong 5 phút tiếp theo. Việc này giúp ngăn quy trình tự động hoá kích hoạt liên tục.

Để áp dụng tính năng chặn điều kiện kích hoạt cho quy trình tự động hoá, hãy sử dụng từ khoá suppressFor cùng với đối số java.time.Duration thể hiện thời gian chờ trước khi phản hồi các điều kiện kích hoạt tiếp theo. Thời gian chặn có thể ngắn nhất là 5 giây hoặc dài nhất là 24 giờ.

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

Xin lưu ý rằng việc chặn điều kiện kích hoạt sẽ ảnh hưởng đến tất cả starters trong một quy trình tự động hoá trước suppressFor.

Giới hạn số lần thực thi

Bạn có thể giới hạn số lần một quy trình tự động hoá được phép chạy.

Ví dụ: bạn có thể muốn thiết lập một quy trình tự động hoá một lần để chạy máy hút bụi khi bạn vắng nhà trong ngày.

Để thực hiện việc này, hãy đặt trường siêu dữ liệu maxExecutionCount của quy trình tự động hoá. Ví dụ sau đây là một quy trình tự động hoá chỉ có thể thực thi một lần:

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()) }
  }
}

Quy trình tự động hoá sẽ bị xoá ngay sau khi hoàn tất lần thực thi cuối cùng và đạt đến maxExecutionCount. Mục nhật ký của quy trình tự động hoá vẫn còn trong thẻ Google Home app (GHA) Hoạt động, bao gồm cả automation_id.

Đặt thuộc tính đặc điểm trong một hành động

Cách đặt giá trị của thuộc tính đặc điểm:

  1. Tạo một nút update trong nút action, bao gồm cả đặc điểm liên quan làm đối số cho nút update:
    action(deviceReference, deviceType) {
      update(trait) {
    
      }
    }
  2. Trong nút update, đối với mỗi thuộc tính cần sửa đổi, hãy sử dụng hàm biến đổi và truyền giá trị mới cho hàm đó. Cách đặt tên cho hàm biến đổi:
    1. Viết hoa tên thuộc tính
    2. Thêm tiền tố là từ set.
    Ví dụ: để cập nhật một thuộc tính có tên là defaultMoveRate, bạn sẽ sử dụng hàm biến đổi có tên là setDefaultMoveRate.

Xin lưu ý rằng một nút update có thể có nhiều hàm biến đổi. Sau đây là ví dụ về việc cập nhật hai thuộc tính:

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