Z tego przewodnika dowiesz się, jak używać różnych węzłów Automation DSL do tworzenia automatyzacji.
Cały kod Automation DSL znajduje się w jednym węźle automation. Węzeł automation stanowi granicę między zewnętrznym kontekstem języka Kotlin a osadzonym kontekstem DSL.
Przepływ sekwencyjny
Przepływ sekwencyjny to domyślny typ przepływu automatyzacji.
Oto bardzo podstawowy szablon Automation DSL, który korzysta z przepływu sekwencyjnego składającego się z polecenia inicjującego, warunku i działania:
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 {...}
}
}
Możesz go udoskonalić, dodając dodatkowe węzły.
Polecenie inicjujące
Węzły polecenia inicjującego określają początkowe okoliczności, które aktywują automatyzację. Może to być np. zmiana stanu lub wartości. Automatyzacja musi mieć co najmniej 1 polecenie inicjujące, w przeciwnym razie nie przejdzie weryfikacji. Aby dodać do automatyzacji więcej niż 1 polecenie inicjujące, musisz użyć węzła select.
Polecenie inicjujące na podstawie atrybutu cechy
Deklarując węzeł polecenia inicjującego, który jest oparty na atrybucie cechy, określ:
- urządzenie,
- typ urządzenia, do którego należy cecha,
- cechę.
starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)
Parametr typu urządzenia jest wymagany, ponieważ pozwala określić, do którego typu urządzenia w ramach urządzenia odnosi się automatyzacja. Urządzenie może się np. składać z
FanDevice
i
HeatingCoolingUnitDevice,
z których oba zawierają cechę
OnOff
. Określenie typu urządzenia eliminuje niejednoznaczność co do tego, która część urządzenia wywołuje automatyzację.
Polecenie inicjujące na podstawie zdarzenia
Deklarując węzeł polecenia inicjującego, który jest oparty na zdarzeniu, określ:
- urządzenie,
- typ urządzenia, do którego należy cecha,
- zdarzenie.
starter<_>(doorBell, GoogleDoorbellDevice, DoorbellPressed)
Polecenie inicjujące na podstawie struktury i zdarzenia z parametrami
Niektóre zdarzenia mogą mieć parametry, dlatego te parametry muszą być też uwzględnione w poleceniu inicjującym.
To polecenie inicjujące używa np.
Time cechy ScheduledTimeEvent, aby aktywować automatyzację o 7:00:
val earlyMorning = starter<_>(structure, Time.ScheduledTimeEvent) {
parameter(Time.ScheduledTimeEvent.clockTime(
LocalTime.of(7, 0, 0, 0)))
}
Polecenie inicjujące na podstawie pogody
W poleceniu inicjującym możesz określić aktualne lub prognozowane warunki pogodowe za pomocą cechy Weather:
val weatherState = starter<_>(structure, trait = Weather)
Na stronie Przykłady automatyzacji znajdziesz przykład Close the blinds if it is likely to rain (Zasłoń rolety, jeśli prawdopodobnie będzie padać).
Ręczne polecenie inicjujące
Ręczne polecenie inicjujące to specjalny typ polecenia inicjującego, który umożliwia użytkownikowi ręczne uruchomienie automatyzacji.
Deklarując ręczne polecenie inicjujące:
- Nie określaj cechy ani typu urządzenia.
- Podaj element interfejsu, który wywołuje
Automation.execute().
Jeśli umieścisz ręczne polecenie inicjujące w przepływie select wraz z innym poleceniem inicjującym, ręczne polecenie inicjujące zastąpi inne polecenie inicjujące:
select {
manualStarter()
starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)
}
Pamiętaj, że wszystkie węzły condition następujące po ręcznym poleceniu inicjującym zostaną ocenione i mogą zablokować wykonanie automatyzacji w zależności od wyrażenia condition.
Jednym ze sposobów na skonstruowanie automatyzacji tak, aby węzły condition nie blokowały automatyzacji aktywowanej ręcznym poleceniem inicjującym, jest umieszczenie innego polecenia inicjującego w osobnym przepływie sekwencyjnym wraz z jego condition:
automation_graph {
sequential {
select {
sequential {
starter<_>(...)
condition {...}
}
sequential {
manualStarter()
}
}
action {...}
}
}
Odwoływanie się do wartości atrybutu
Aby użyć wartości atrybutu w wyrażeniu, użyj tej składni.
Za pomocą stateReader:
val time = stateReader<_>(structure, Structure, Time)
val currTime = time.currentTime
Za pomocą starter:
val starterNode = starter<_>(device1, LaundryWasherDevice, OnOff)
condition() {
expression = starterNode.onOff equals true
}
Węzły i wyrażenia warunków
Węzeł warunku reprezentuje punkt decyzyjny, który określa, czy automatyzacja będzie kontynuowana. Automatyzacja może mieć wiele węzłów condition.
Jeśli wyrażenie dowolnego węzła condition przyjmie wartość false, wykonanie całej automatyzacji zostanie zakończone.
W węźle condition możesz łączyć wiele kryteriów warunku za pomocą
różnych operatorów, o ile wyrażenie
przyjmuje pojedynczą
wartość logiczną. Jeśli wartość wynikowa to true, warunek jest spełniony, a automatyzacja kontynuuje wykonywanie następnego węzła. Jeśli wartość to false, automatyzacja zatrzymuje się w tym momencie.
Wyrażenia są tworzone podobnie jak wyrażenia w języku Kotlin i mogą zawierać wartości pierwotne, takie jak liczby, znaki, ciągi znaków i wartości logiczne, a także wartości wyliczeniowe. Grupowanie wyrażeń podrzędnych za pomocą nawiasów pozwala kontrolować kolejność ich oceniania.
Oto przykład condition, który łączy wiele wyrażeń podrzędnych w jedno wyrażenie:
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)
}
Możesz odwoływać się do wartości cechy, do której dostęp uzyskano za pomocą polecenia inicjującego:
val starterNode = starter<_>(device, OnOff)
condition() { expression = starterNode.onOff equals true }
stateReader
Innym sposobem na odwoływanie się do wartości atrybutów cech w węźle condition jest użycie węzła stateReader.
Aby to zrobić, najpierw przechwyć wartość atrybutu cechy w węźle stateReader. stateReader przyjmuje jako argumenty structure i cechę:
import com.google.home.automation.stateReader
...
val filterMonitoringState = stateReader<_>(structure, ActivatedCarbonFilterMonitoring)
Następnie odwołaj się do stateReader w węźle condition:
condition() {
expression =
filterMonitoringState.changeIndication
.equals(ChangeIndicationEnum.Warning)
}
W węźle condition można używać wielu stateReaders za pomocą operatorów porównania i
logicznych:
val armState = stateReader<_>(doorLock, DoorLockDevice, ArmDisarm )
val doorLockState = stateReader<_>(doorLock, DoorLockDevice, DoorLock)
condition() {
expression =
(armState.armState equals true)
and
(doorLockState.lockState equals true)
}
Czas trwania warunku
Oprócz wyrażenia logicznego w warunku możesz określić przedział czasu, w którym wyrażenie musi być prawdziwe, aby można było uruchomić automatyzację. Możesz np. zdefiniować warunek, który uruchomi się tylko wtedy, gdy światło jest włączone przez 10 minut.
condition {
expression(lightStateReader.onOff == true)
forDuration(Duration.ofMinutes(10))
}
Czas trwania może wynosić od 5 sekund do 24 godzin.
Węzły działań
Węzeł działania to miejsce, w którym odbywa się praca automatyzacji.
W tym przykładzie działanie wywołuje
AssistantBroadcast
cechy
broadcast() polecenie:
action(device, SpeakerDevice) {
command(AssistantBroadcast.broadcast("Intruder detected!"))
}
Instrukcje importowania
Podczas tworzenia automatyzacji nie zawsze jest oczywiste, jak importować różne elementy interfejsów Home API do kodu.
Atrybuty cech są importowane z obiektu Companion cechy:
import com.google.home.matter.standard.OnOff.Companion.onOff
Struktury danych zdefiniowane przez cechę są importowane z klasy cechy, której nazwa kończy się na „-Trait”:
import com.google.home.matter.standard.MediaPlaybackTrait.PlaybackStateEnum
Polecenia cech są importowane z obiektu Companion cechy:
import com.google.home.matter.standard.Thermostat.Companion.setTemperatureSetpointHold