WebUI Programmlogik - einfach erklärt am "lebenden Objekt"
Verfasst: 13.07.2018, 18:28
Hallo Leute!
Das Thema wurde schon oft diskutiert. Zuletzt wieder hier. An Beschreibungen herrscht kein Mangel (z.B. hier). Die Frage ist: Wie kann man das möglichst einfach (aber doch korrekt) erklären?
Update 21.2.2019: Testfall 6 und 7 im Skript ergänzt,
Update 27.2.2019: Auslösebedingung exakter beschrieben
Update 5.3. 2019: Auslösebedingung im Beispiel rot markiert
Also mal ein neuer Ansatz. Nicht beschreiben, sondern am "lebenden Objekt" zeigen.
Dazu habe ich
Mit diesem "Handwerkszeug" kann man natürlich recht einfach auch andere Situationen durchspielen. Zum Beispiel prüfen, was passiert wenn man die CCU neu bootet, oder das Programm manuell startet (der erste Aktivitäten Zweig wird durchlaufen und "Trace" steht auf: "_test: 1. Dann... (_test_var2=1)" auch wenn _test_var2 = 0 ist).
Als Erklärung, warum das alles so ist, am Ende doch noch der Versuch einer möglichst kurzen Beschreibung. Unterscheide zwischen
**) Beim Neustarten der CCU werden vor dem Auslösen von Programmen alle Systemvariablen und Datenpunkte (Status von Geräten) auf den zuletzt bekannten Zustand gesetzt. Ausnahme ist die Systemvariable "Anwesenheit": diese wird immer auf "wahr" gesetzt. Das kann man dazu verwenden, um zu verhindern, dass ein "Aktivität:"-Block bei Neustart ausgeführt wird (siehe z.B. hier).
gzi
Das Thema wurde schon oft diskutiert. Zuletzt wieder hier. An Beschreibungen herrscht kein Mangel (z.B. hier). Die Frage ist: Wie kann man das möglichst einfach (aber doch korrekt) erklären?
Update 21.2.2019: Testfall 6 und 7 im Skript ergänzt,
Update 27.2.2019: Auslösebedingung exakter beschrieben
Update 5.3. 2019: Auslösebedingung im Beispiel rot markiert
Also mal ein neuer Ansatz. Nicht beschreiben, sondern am "lebenden Objekt" zeigen.
Dazu habe ich
- Systemvariablen angelegt _test_var1 - _test_var3 (jeweils integer) sowie Trace (string)
- Ein Skript mit Testfällen erstellt, das den _test_var unterschiedliche Werte zuweist
Code: Alles auswählen
! Testscript: manuell starten! ! . ! Testfall 1 ! . WriteLine("Testfall 1: "); ! Reset dom.GetObject("_test_var1").State(0); dom.GetObject("_test_var2").State(0); dom.GetObject("_test_var3").State(0); dom.GetObject("Trace").State("none"); ! Programm _test_pgm auslösen dom.GetObject("_test_var2").State(1); WriteLine("_test_pgm: Auslöser _test_var1, var2=1, var3=0"); dom.GetObject("_test_var1").State(1); ! Ergebnis ausgeben - die wiederholten GetObject Anweisungen dienen nur dazu, dass nach dem Auslösen ! des Programms ein wenig Zeit vergeht, damit das Programm die Trace Variable setzen kann, bevor sie im ! WriteLine weiter unten ausgegeben wird. dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); WriteLine("Testergebnis: "#dom.GetObject("Trace").Value()); ! . ! Testfall 2a ! . WriteLine("Testfall 2a: "); ! Reset dom.GetObject("_test_var1").State(0); dom.GetObject("_test_var2").State(0); dom.GetObject("_test_var3").State(0); dom.GetObject("Trace").State("none"); ! Programm _test_pgm auslösen dom.GetObject("_test_var2").State(2); WriteLine("Auslöser _test_var1, var2=2, var3=0"); dom.GetObject("_test_var1").State(1); ! Ergebnis ausgeben dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); WriteLine("Testergebnis: "#dom.GetObject("Trace").Value()); ! . ! Testfall 2b ! . WriteLine("Testfall 2b: "); ! Reset dom.GetObject("_test_var1").State(0); dom.GetObject("_test_var2").State(0); dom.GetObject("_test_var3").State(0); dom.GetObject("Trace").State("none"); ! Programm _test_pgm auslösen dom.GetObject("_test_var2").State(2); WriteLine("Auslöser _test_var3"); dom.GetObject("_test_var3").State(1); ! Ergebnis ausgeben dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); WriteLine("Testergebnis: "#dom.GetObject("Trace").Value()); ! . ! Testfall 3 ! . WriteLine("Testfall 3: "); ! Reset dom.GetObject("_test_var1").State(0); dom.GetObject("_test_var2").State(0); dom.GetObject("_test_var3").State(0); dom.GetObject("Trace").State("none"); ! Programm _test_pgm auslösen dom.GetObject("_test_var2").State(3); WriteLine("Auslöser _test_var3, var1=0, var2=3"); dom.GetObject("_test_var3").State(1); ! Ergebnis ausgeben dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); WriteLine("Testergebnis: "#dom.GetObject("Trace").Value()); ! . ! Testfall 5 ! . WriteLine("Testfall 5: "); ! Reset dom.GetObject("_test_var1").State(0); dom.GetObject("_test_var2").State(0); dom.GetObject("_test_var3").State(0); dom.GetObject("Trace").State("none"); ! Programm _test_pgm auslösen WriteLine("Auslöser _test_var1, var2=0, var3=0"); dom.GetObject("_test_var1").State(1); ! Ergebnis ausgeben dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); WriteLine("Testergebnis: "#dom.GetObject("Trace").Value()); ! . ! Testfall 5b ! . WriteLine("Testfall 5b: "); ! Reset dom.GetObject("_test_var1").State(0); dom.GetObject("_test_var2").State(0); dom.GetObject("_test_var3").State(0); dom.GetObject("Trace").State("none"); ! Programm _test_pgm auslösen WriteLine("Auslöser _test_var3, var2=1, var3=0"); dom.GetObject("_test_var2").State(1); dom.GetObject("_test_var3").State(1); ! Ergebnis ausgeben dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); WriteLine("Testergebnis: "#dom.GetObject("Trace").Value()); ! . ! Testfall 5c ! . WriteLine("Testfall 5c: "); ! reset dom.GetObject("Trace").State("none"); ! Auslöservariable auf irgendeinen wert ändern WriteLine("test_var1=57, var2=1, var3=0"); dom.GetObject("_test_var1").State(57); ! Ergebnis ausgeben - die wiederholten GetObject Anweisungen dienen nur dazu, dass nach dem Auslösen ! des Programms ein wenig Zeit vergeht, damit das Programm die Trace Variable setzen kann, bevor sie im ! WriteLine weiter unten ausgegeben wird. dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); WriteLine("Testergebnis: "#dom.GetObject("Trace").Value()); ! Testscript: manuell starten! ! . ! Testfall 6 ! . WriteLine("Testfall 6: "); ! Reset dom.GetObject("_test_var1").State(0); dom.GetObject("Trace").State(""); ! Programm _test_pgm_sonst auslösen dom.GetObject("_test_var1").State(150); WriteLine("Auslöser _test_var1=150"); ! Ergebnis ausgeben - die wiederholten GetObejt Anweisungen dienen nur dazu, dass nach dem Auslösen ! des Programms ein wenig Zeit vergeht, damit das Programm die Trace Variable setzen kann, bevor sie im ! WriteLine weiter unten ausgegeben wird. dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); WriteLine("Testergebnis: "#dom.GetObject("Trace").Value()); ! . ! Testfall 7 ! . WriteLine("Testfall 7: "); ! Programm _test_pgm_sonst auslösen dom.GetObject("_test_var1").State(300); WriteLine("Auslöser _test_var1=300"); ! Ergebnis ausgeben - die wiederholten GetObejt Anweisungen dienen nur dazz, dass nach dem Auslösen ! des Programms ein wenig Zeit vergeht, damit das Programm die Trace Variable setzen kann, bevor sie im ! WriteLine weiter unten ausgegeben wird. dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); dom.GetObject("Trace").Value(); WriteLine("Testergebnis: "#dom.GetObject("Trace").Value()); ! .
- zwei Programme erstellt, die durch Werteänderungen von _test_var1 und _test_var3 ausgelöst werden.
- Dann mit "Skript Testen" das Skript laufen lassen.
Code: Alles auswählen
Testfall 1:
_test_pgm: Auslöser _test_var1, var2=1, var3=0
Testergebnis: _test: 1. Dann... (_test_var2=1)
Testfall 2a:
Auslöser _test_var1, var2=2, var3=0
Testergebnis: _test: 2. Sonst, wenn... _test_var2 =2
Testfall 2b:
Auslöser _test_var3
Testergebnis: _test: 2. Sonst, wenn... _test_var2 =2
Testfall 3:
Auslöser _test_var3, var1=0, var2=3
Testergebnis: _test: 3. Sonst, wenn... (_test_var2 = egal) =1
Testfall 5:
Auslöser _test_var1, var2=0, var3=0
Testergebnis: _test: 5. Sonst... (Zweig ohne Bedingungen)
Testfall 5b:
Auslöser _test_var3, var2=1, var3=0
Testergebnis: _test: 5. Sonst... (Zweig ohne Bedingungen)
Testfall 5c:
test_var1=57, var2=1, var3=0
Testergebnis: none
Testfall 6:
Auslöser _test_var1=150
Testergebnis: _test_pgm_sonst: Aktivität:Dann durchlaufen
Testfall 7:
Auslöser _test_var1=300
Testergebnis: _test_pgm_sonst: Aktivität:Sonst durchlaufen
Als Erklärung, warum das alles so ist, am Ende doch noch der Versuch einer möglichst kurzen Beschreibung. Unterscheide zwischen
- dem Ereignis (Auslöser)
- der Bedingung, ob ein Programm ausgelöst(gestartet) wird (Auslösebedingung) und
- den Bedingungen, die steuern welcher "Aktivität:"-Block im Programm ausgeführt wird (Auswahlbedingung)
- Programme werden ausgelöst, wenn sie entweder
- manuell (übers WebUI) gestartet werden,
- wenn die CCU neu gestartet wird **) oder
- wenn irgendeine im Programm angegebene Auslösebedingung *) zutrifft. Das kann die Änderung einer Systemvariaben, die kein String ist (wie im Beispiel oben) sein, die Änderung eines Geräte-Datenpunkts oder eine Zeit-Steuerung . Das _test_pgm wird also ausgelöst wenn sich entweder _test_var1 oder _test_var3 ändert
- Es ist egal wo, also in welchem "Bedingung:"-Abschnitt eine Auslösebedingung steht. Sie kann also auch unterhalb des "Aktivität: Dann..."-Blocks stehn, der zur Ausführung kommt bzw. in irgend einem "Bedingung: "-Block stehen. Siehe Testfall 2b
- Nach dem Starten/Auslösen des Programms wird der erste (und kein weiterer!) "Aktivität: Dann..."- Block ausgeführt für den die Auswahlbedingungen (im obigen Beispiel grün eingerahmt) in dem unmittelbar davor stehenden "Bedingung:"-Block zutreffen **).
- Das sind neben "nur prüfen"-Bedingungen auch Bedingungen die in der selben Zeile wie ein Auslöser stehen (oben z.B. "im Wertebereich von bis").
- AUSNAHME: Wird das Programm manuell gestartet/ausgelöst dann wird immer der erste "Aktivität: Dann..."- Block ausgeführt, egal welche Auslöse- oder Auswahlbedingungen davor stehen.
- Alle anderen "Aktivität: Dann..."-Blöcke werden nicht durchlaufen. Es gibt also keine geschachtelten IF's wie in anderen Programmiersprachen.
- Wird das Programm zwar ausgelöst, aber es trifft keine Auswahlbedingung für einen "Aktivität: Dann..."-Block zu, dann wird der "Aktivität: Sonst..."-Block durchlaufen
**) Beim Neustarten der CCU werden vor dem Auslösen von Programmen alle Systemvariablen und Datenpunkte (Status von Geräten) auf den zuletzt bekannten Zustand gesetzt. Ausnahme ist die Systemvariable "Anwesenheit": diese wird immer auf "wahr" gesetzt. Das kann man dazu verwenden, um zu verhindern, dass ein "Aktivität:"-Block bei Neustart ausgeführt wird (siehe z.B. hier).
gzi