Руководство по Android DSL для сложных автоматизаций

С помощью Automation DSL можно создавать более сложные сценарии автоматизации, чем те, которые описаны в руководстве по DSL для базовой автоматизации на устройствах Android.

Последовательность с несколькими действиями

Последовательность с несколькими действиями

Программа может выполнять несколько действий. Например, вместо одного узла action можно использовать несколько узлов action, которые выполняются последовательно:

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

Последовательное выполнение с несколькими параллельными действиями

Последовательное выполнение с несколькими параллельными действиями

Если в узле parallel разместить несколько узлов action, действия будут выполняться одновременно.

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

Если в узле sequential есть узлы action, которые следуют за узлом 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, представляющий собой время паузы перед продолжением выполнения. Приостановка может длиться от пяти секунд до 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)
  }
}