To jest omówienie podstawowych koncepcji języka DSL automatyzacji w Androidzie.
Komponenty automatyzacji
Automatyzacja składa się z tych podstawowych komponentów, które są zwykle oceniane w tej kolejności:
- Polecenie inicjujące – określa warunki początkowe, które aktywują automatyzację, np. zmianę cechy. Automatyzacja musi mieć polecenie inicjujące.
- Warunek – wszelkie dodatkowe ograniczenia, które należy ocenić po aktywowaniu automatyzacji. Aby działania automatyzacji mogły być kontynuowane, wyrażenie w warunku musi przyjmować wartość
true. - Działanie – polecenia lub aktualizacje stanu, które są wykonywane po spełnieniu wszystkich warunków.
Możesz na przykład mieć automatyzację, która przyciemnia światła w pomieszczeniu, gdy telewizor w tym pomieszczeniu jest włączony między zachodem a wschodem słońca. W tym przykładzie:
- Polecenie inicjujące – telewizor został włączony, co jest zmianą stanu cechy telewizora.
- Warunek – oceniany jest bieżący czas w domu, w którym znajduje się telewizor.
- Działanie – światła w tym samym pomieszczeniu co telewizor są przyciemniane.
Automatyzacja zostanie aktywowana, gdy telewizor w pomieszczeniu zostanie włączony, ale zostanie wykonana tylko wtedy, gdy zostanie spełniony warunek „czas jest między zachodem a wschodem słońca”.
Oprócz podstawowej struktury automatyzacje w interfejsach Home API zawierają też metadane, takie jak name (nazwa) i description (opis), które mogą być używane do identyfikowania ich przez deweloperów i użytkowników.
Węzły
W interfejsach Home API logiczna struktura automatyzacji składa się z węzłów. Węzły to abstrakcyjne, wielokrotnego użytku jednostki, które reprezentują zachowania encji lub przepływy wykonania. Każdy węzeł może mieć zmienne wejściowe i wyjściowe, które mogą być używane przez inne węzły.
| Węzeł | Typ węzła | Implementacja w Kotlinie | Opis |
|---|---|---|---|
| Starter | Zachowanie |
StarterNodeDsl
|
Uruchamia automatyzację, gdy zmieni się stan cechy (dowolny atrybut). |
| StateReader | Zachowanie |
StateReaderNodeDsl
|
Odczytuje atrybut cechy i umożliwia przechwycenie jego wartości do użycia w węzłach warunków. |
| Action | Zachowanie |
ActionNodeDsl
|
Wywołuje polecenia cech. |
| Sequential | Przepływ wykonania |
SequentialFlow
|
Wykonuje zagnieżdżone węzły działań w sekwencji. Jest to domyślne zachowanie wykonania. |
| Parallel | Przepływ wykonania |
ParallelFlow
|
Wykonuje zagnieżdżone węzły działań równolegle. |
| Condition | Przepływ wykonania |
ConditionNodeDsl
|
Warunkowo zmienia przepływ wykonania na podstawie ocen wyrażeń logicznych. Warunki mogą być powiązane z poleceniem inicjującym (warunki specyficzne dla polecenia inicjującego ) lub globalne (dotyczą wszystkich poleceń inicjujących). |
| Select | Przepływ wykonania |
SelectFlow
|
Umożliwia aktywowanie automatyzacji przez więcej niż 1 polecenie inicjujące. |
| IfFlow | Przepływ wykonania |
IfFlowDsl
|
Uruchamia co najwyżej 1 działanie (lub gałąź) na podstawie tego, który warunek (jeśli występuje) przyjmuje wartość true (podobnie jak instrukcja if-then-else). |
| Expression | Wartość |
Expression
|
Może to być wartość atrybutu cechy, stała lub literał i musi przyjmować wartość listy, liczby, wartości logicznej lub ciągu znaków. |
Węzły zachowań
Węzły takie jak polecenia inicjujące i działania to węzły zachowań. Polecenia inicjujące aktywują automatyzację na podstawie zmian atrybutów urządzenia. Działania wydają polecenia urządzenia lub aktualizują atrybuty.
Węzły zachowań są zwykle powiązane z cechami urządzenia i stanem cechy wyjściowej, który jest używany jako dane wejściowe w innych węzłach.
Węzły przepływu wykonania
Niektóre węzły reprezentują przepływy wykonania, np. sekwencyjne i równoległe. Każdy z tych węzłów zawiera węzły zachowań, które definiują automatyzację.
Na przykład przepływ sekwencyjny może zawierać węzły, które są wykonywane w kolejności. Zwykle są to polecenie inicjujące, warunek i działanie.
Przepływ równoległy może mieć kilka węzłów działań wykonywanych w tym samym czasie, np. włączanie kilku świateł jednocześnie. Węzły następujące po przepływie równoległym nie zostaną wykonane, dopóki nie zakończą się wszystkie gałęzie przepływu równoległego.
Innym typem przepływu wykonania jest przepływ warunku, który może zmieniać przepływ wykonania na podstawie oceny wyrażenia.
Możesz na przykład mieć automatyzację, która wykonuje działanie w zależności od tego, czy jest noc. Węzeł warunku sprawdza porę dnia, a następnie podąża odpowiednią ścieżką wykonania na podstawie tej oceny.
Przepływ wyboru jest przydatny, gdy chcesz mieć więcej niż 1 polecenie inicjujące, które może aktywować automatyzację. Gdy umieścisz co najmniej 2 polecenia inicjujące w przepływie select, dowolne z nich może aktywować automatyzację.
Możesz na przykład napisać automatyzację, która opuszcza rolety o zachodzie słońca, jeśli temperatura wzrośnie powyżej określonego progu lub jeśli jasność przekroczy próg. Każdy z tych scenariuszy jest obsługiwany przez 3 oddzielne polecenia inicjujące, a wszystkie 3 będą zawarte w przepływie select.
Przepływ if-then-else (IfFlow) umożliwia rozgałęzianie warunkowego wykonania w ramach automatyzacji. W przeciwieństwie do węzła condition, który zatrzymuje całą automatyzację, jeśli warunek ma wartość false, przepływ if-then-else warunkowo wykonuje określone działania, gdy warunek jest spełniony, i może powrócić do alternatywnych warunków lub działań rezerwowych albo przejść do kolejnych węzłów w automatyzacji. Więcej informacji znajdziesz w artykule
Wykonanie warunkowe.
Zagnieżdżone przepływy
W złożonych automatyzacjach węzły przepływu wykonania mogą być też zagnieżdżone. Możesz na przykład mieć przepływ sekwencyjny, który wykonuje przepływ równoległy.
Węzły DSL można zagnieżdżać i łączyć na różne sposoby, aby spełnić określone potrzeby, zgodnie z ograniczeniami opisanymi w tabeli poniżej. Kolumna Builder zawiera link do dokumentacji bezpiecznego typu buildera w Kotlinie, która szczegółowo opisuje, co można używać w każdym typie węzła.
| Węzeł | Może zawierać te typy węzłów i dane | Musi znajdować się w jednym z tych typów węzłów |
|---|---|---|
| Starter | Wyrażenie | Select, Sequential |
| ManualStarter | Select, Sequential | |
| StateReader | Wyrażenie (zwykle składające się z wartości atrybutu cechy) | IfFlow, Parallel, Sequential |
| Action | Polecenie, encja, wyrażenie | IfFlow, Parallel, Select, Sequential |
| Sequential | IfFlow, Parallel, Select, Sequential | |
| Parallel | Działanie | IfFlow, Sequential |
| Condition | Wyrażenie | IfFlow, Parallel, Sequential |
| Select | Warunek, sekwencyjny, polecenie inicjujące, ManualStarter | Sequential i musi być pierwszym węzłem w przepływie |
| IfFlow | Działanie, warunek, opóźnienie, IfFlow, równoległy, sekwencyjny, StateReader, Suppression | Sequential |
DSL automatyzacji
W interfejsach Home API automatyzacje są definiowane za pomocą języka DSL automatyzacji (Domain-Specific Language). DSL automatyzacji jest implementowany jako język DSL (domain-specific language), który używa bezpiecznych typów builderów w Kotlinie i jest specjalnie zaprojektowany do definiowania szablonów automatyzacji.
Gdy automatyzacja jest kompilowana, bezpieczne typy builderów w Kotlinie generują klasy danych w Kotlinie, które są następnie serializowane do formatu JSON bufora protokołu, który jest używany do wywoływania usług automatyzacji Google.
DSL automatyzacji upraszcza i usprawnia proces tworzenia automatyzacji. Natywnie używa tego samego modelu danych cech standardu Matter i cech smart home dostępnych w interfejsie Device API.
DSL automatyzacji definiuje też logikę automatyzacji w kategoriach abstrakcyjnych typów urządzeń, a nie konkretnych instancji urządzeń znajdujących się w domu użytkownika. Umożliwia deweloperowi podawanie parametrów wejściowych, które mogą być używane w czasie działania do określania rzeczywistych instancji urządzeń, a także innych ważnych wartości parametrów.
Składnia DSL jest podobna do składni Kotliny i jest równie bezpieczna pod względem typów, ale automatyzacja napisana w DSL automatyzacji jest prostsza i bardziej zwięzła niż ta sama automatyzacja napisana w czystej Kotlinie.
Przykład
Oto przykład automatyzacji, która włącza urządzenie, napisanej za pomocą DSL automatyzacji:
val automation = automation {
name = "MyFirstAutomation"
description = "If light1 is on, turn on light2."
isActive = true
sequential {
val onOffTrait = starter<_>(device1, OnOffLightDevice, OnOff)
condition() { expression = onOffTrait.onOff equals true }
action(device2, OnOffLightDevice) { command(OnOff.on()) }
}
}
Ta automatyzacja jest bardzo prosta: gdy device1 (światło) się włączy (atrybut onOff zmieni się na true), wysyła polecenie on() , aby włączyć device2.
Automatyzacja używa węzła sequential, który wskazuje, że jego węzły będą uruchamiane w kolejności.
W węźle sequential znajdują się węzły zachowań, takie jak starter, condition i action. Dane wyjściowe węzła starter są przypisywane do zmiennej, która jest używana w węźle condition.