Руководство по Android DSL

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

Все DSL-документы автоматизации размещаются в одном узле automation . Узел automation образует границу между внешним контекстом языка Kotlin и встроенным контекстом DSL.

Последовательный поток

Последовательный поток является типом потока автоматизации по умолчанию.

Пример последовательного DSL

Вот очень простой шаблон Automation DSL, который использует последовательный поток, состоящий из стартера, условия и действия:


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 {...}
  }
}

Его можно усовершенствовать, добавив дополнительные узлы.

Стартер

Узлы-стартеры определяют начальные условия активации автоматизации. Например, изменение состояния или значения. У автоматизации должен быть хотя бы один стартер, иначе она не пройдет валидацию. Чтобы добавить в автоматизацию более одного стартера, необходимо использовать узел select .

Стартер на основе атрибута черты характера

При объявлении начального узла, основанного на атрибуте черты, укажите:

  • устройство
  • тип устройства, к которому принадлежит признак
  • черта
starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)

Параметр типа устройства является обязательным, поскольку он позволяет указать, к какому типу устройств внутри устройства относится автоматизация. Например, устройство может состоять из FanDevice и HeatingCoolingUnitDevice , оба из которых содержат свойство OnOff . Указание типа устройства исключает неоднозначность в отношении того, какая часть устройства запускает автоматизацию.

Стартер на основе события

При объявлении стартового узла, основанного на событии, укажите:

  • устройство
  • тип устройства, к которому принадлежит признак
  • событие
starter<_>(doorBell, GoogleDoorbellDevice, DoorbellPressed)

Стартер на основе структуры и события с параметрами

Некоторые события могут иметь параметры, поэтому эти параметры также необходимо включить в стартер.

Например, этот стартер использует ScheduledTimeEvent свойства Time для активации автоматизации в 7:00 утра:

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

Ручной стартер

Ручной пускатель — это особый тип пускателя, который позволяет пользователю вручную запускать автоматику.

При объявлении ручного стартера:

  • Не указывайте характеристику или тип устройства.
  • Предоставьте элемент пользовательского интерфейса, который вызывает Automation.execute() .

При размещении ручного пускателя в select потоке вместе с другим пускателем ручной пускатель имеет приоритет над другим пускателем:

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

Обратите внимание, что любые узлы condition , следующие за ручным пускателем, будут оценены и могут заблокировать выполнение автоматизации в зависимости от выражения condition .

Отделение ручного стартера от условного

Один из способов структурировать автоматизацию таким образом, чтобы узлы condition не блокировали автоматизацию, активированную с помощью ручного пускателя, — поместить другой пускатель в отдельный последовательный поток вместе с его condition :

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

Ссылка на значение атрибута

Чтобы использовать значение атрибута в выражении, используйте следующий синтаксис.

С stateReader :

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

Со starter :

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

Условные узлы и выражения

Узел условия представляет собой точку принятия решения, которая определяет, будет ли продолжена автоматизация. Автоматизация может иметь несколько узлов condition . Если выражение любого узла condition принимает значение false , выполнение всей автоматизации завершается.

В узле condition можно комбинировать несколько условий с помощью различных операторов , при условии, что выражение возвращает одно логическое значение. Если результирующее значение равно true , условие выполняется, и автоматизация продолжает выполнение следующего узла. Если оно равно false , автоматизация останавливает выполнение в этой точке.

Выражения формируются аналогично выражениям в Kotlin и могут содержать примитивные значения, такие как числа, символы, строки и логические значения, а также значения Enum. Группировка подвыражений с помощью скобок позволяет контролировать порядок их вычисления.

Вот пример condition , которое объединяет несколько подвыражений в одно выражение:

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

Вы можете ссылаться на значение признака, доступ к которому осуществляется через стартер:

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

stateReader

Другой способ ссылки на значения атрибутов признаков в узле condition — использование узла stateReader .

Для этого сначала необходимо получить значение атрибута типажа в узле stateReader . stateReader принимает structure и тип в качестве аргументов:

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

Затем обратитесь к stateReader в узле condition :

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

Используя операторы сравнения и логические операторы , в узле condition можно использовать несколько stateReaders :

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

Длительность состояния

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

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

Продолжительность может варьироваться от одной до 30 минут.

Узлы действий

Узел действия — это место, где происходит автоматизация. В этом примере действие вызывает команду broadcast() трейта AssistantBroadcast :

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

Импортные заявления

При разработке автоматизации не всегда очевидно, как импортировать различные элементы Home API в свой код.

Атрибуты признака импортируются из объекта Companion признака:

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

Структуры данных, определяемые признаком, импортируются из класса признака, имя которого заканчивается на «-Trait»:

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

Команды признаков импортируются из объекта Companion признака:

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