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 thao tác tự động có thể làm nhiều việc. Ví dụ: thay vì một nút action duy nhất, 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, các thao tác 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 này sẽ đợi thực thi cho đến khi tất cả các nút trong nút parallel hoàn tất quá trình thực thi.

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 thao tác hoặc đường dẫn khác nhau dựa trên các điều kiện thời gian chạy), hãy sử dụng câu lệnh if-then-else. Các câu lệnh này được tạo bằng các khối DSL luồng điều khiển có điều kiện: ifThen, elseIforElse.

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

  • Nút condition: 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, 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 đáp ứng điều kiện nào.

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 thao tác hoặc nút DSL được lồng bên trong khối sẽ được thực thi. Nếu giá trị là false, 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 thao tác 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 nhóm hành động khi một điều kiện là đúng và một nhóm hành động thay thế khi điều kiện đó là sai, hãy xâu chuỗi 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!"))
      }
    }
  }
}

Liên kết nhiều điều kiện theo trình tự

Bạn có thể xâu chuỗi 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 đánh giá thành true, 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 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, delayForstateReader.

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

Chậm trễ

Bạn có thể tạm dừng quy trình tự động hoá bằng cách sử dụng từ khoá delayFor. Từ khoá này nhận một đối số java.time.Duration biểu thị khoảng thời gian tạm dừng trước khi tiếp tục thực thi. Thời gian 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()) }
}

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

Tính năng ngăn chặn kích hoạt cho phép quy trình tự động hoá của bạn bỏ qua một starter trong một khoảng thời gian cụ thể sau sự kiện kích hoạt ban đầu. Ví dụ: nếu chế độ tự động hoá có 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 lượng chặn kích hoạt là 5 phút, thì khi starter kích hoạt, chế độ này sẽ không kích hoạt lại trong 5 phút tiếp theo. Điều này ngăn quy trình tự động hoá kích hoạt nhanh nhiều lần.

Để áp dụng tính năng chặn kích hoạt cho quy trình tự động hoá, hãy sử dụng từ khoá suppressFor với đối số java.time.Duration biểu thị khoảng thời gian chờ trước khi phản hồi các sự 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 tính năng chặn kích hoạt sẽ ảnh hưởng đến tất cả starters trong một quy trình tự động hoá diễn ra trước suppressFor.

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

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

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à cả ngày.

Để làm như vậ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ập 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ị cho một 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 dùng một hàm đột biến và truyền giá trị mới cho hàm đó. Cách tạo tên của hàm biến đổi:
    1. Viết hoa tên thuộc tính
    2. Thêm từ set vào trước tên hàm.
    Ví dụ: để cập nhật một thuộc tính có tên là defaultMoveRate, bạn sẽ dùng một hàm sửa đổi có tên là setDefaultMoveRate.

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

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