Endlicher Automat (finite state maschine)

Begonnen von Damian, 10 Februar 2016, 18:14:56

Vorheriges Thema - Nächstes Thema

crusader

Zitat von: Damian am 12 Februar 2016, 09:30:38
ja, [$1] stünde für einen ganzen Vergleich und ist natürlich etwas neues, was jeder lernen muss. Dagegen würde [$this] eq "cmd_1" wohl jeder verstehen.

Wenn man die DOIF-Threads liest, gewinnt man den Eindruck, dass viele Anwender bereits jetzt verwirrt sind, weil sie die unterschiedliche Syntax von Event, State, Reading und Timer (mit oder ohne ergänzende Ausdrücke) nicht so ohne weiteres auseinanderhalten können.

Hinzu kommt im Ausführungsteil die unterschiedliche Bedeutung von '(', '[' und '{' und deren Kombination sowie die Gültigkeit von $EVENT, $event usw.
Wenn dann noch weitere Sonderabfragen dazukommen, läuft DOIF ein bisschen Gefahr, zu einem Universal-Modul zu werden, dass aber weltweit nur noch von fünf Leuten verstanden wird.

Nur meine unmaßgebliche Meinung.

Gruß
crusader


Wuppi68

Zitat von: crusader am 12 Februar 2016, 16:10:44
Wenn man die DOIF-Threads liest, gewinnt man den Eindruck, dass viele Anwender bereits jetzt verwirrt sind, weil sie die unterschiedliche Syntax von Event, State, Reading und Timer (mit oder ohne ergänzende Ausdrücke) nicht so ohne weiteres auseinanderhalten können.

Hinzu kommt im Ausführungsteil die unterschiedliche Bedeutung von '(', '[' und '{' und deren Kombination sowie die Gültigkeit von $EVENT, $event usw.
Wenn dann noch weitere Sonderabfragen dazukommen, läuft DOIF ein bisschen Gefahr, zu einem Universal-Modul zu werden, dass aber weltweit nur noch von fünf Leuten verstanden wird.

Nur meine unmaßgebliche Meinung.

Gruß
crusader

man kann es nutzen, muss es aber nicht

aber ich auch die Gefahr dass es ein Mischung von vi, emacs und edlin wird ...

aber hey, viele Dinge gehen damit deutlich einfacher als ein notify - und dafür ein großes

D a n k e
FHEM unter Proxmox als VM

Damian

ja, ich denke auch wir sollten weiteren Features etwas Zeit lassen, zumindest für Dinge, die jetzt schon gut funktionieren.
Die Selbsttriggerung muss ich mir allerdings noch mal anschauen, denn das ist ja die Mindestvoraussetzung für einen EA.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

crusader

Zitat von: Wuppi68 am 12 Februar 2016, 16:26:39
man kann es nutzen, muss es aber nicht

aber ich auch die Gefahr dass es ein Mischung von vi, emacs und edlin wird ...

aber hey, viele Dinge gehen damit deutlich einfacher als ein notify - und dafür ein großes

D a n k e

Schliesse mich vollumfänglich an.


crusader

Zitat von: Damian am 12 Februar 2016, 16:48:58
ja, ich denke auch wir sollten weiteren Features etwas Zeit lassen, zumindest für Dinge, die jetzt schon gut funktionieren.
Die Selbsttriggerung muss ich mir allerdings noch mal anschauen, denn das ist ja die Mindestvoraussetzung für einen EA.

Verstehe die Problematik nicht.
Selbsttriggerung über Timer-Substates geht doch jetzt schon.

Das selbsttriggernde Lauflicht aus Antwort#1 geht z.B. so:
define LL DOIF ([LL:?start] or [LL] eq "cmd_3")\
    ()\
    ()\
DOELSEIF ([LL] eq "cmd_1") \
    ()\
    ()\
DOELSEIF ([LL] eq "cmd_2")\
    ()\
    ()\
DOELSEIF ([LL:?stop])\

attr LL wait 0,10:0,10:0,10


Starten mit
trigger LL start
Stoppen mit:
trigger LL stop

Wenn man im Ausführungsteil einer ordentlich programmierten FSM auf den Status einwirken will, kann man das doch auch nur, indem man eine definierte Übergangsbedingung setzt, die beim nächsten Durchlauf abgefragt wird.

Bei event-gesteuerten Maschinen kann das zwangsläufig nur zeitverzögert geschehen.

Gruß
cruz 

Damian

Zitat von: crusader am 12 Februar 2016, 22:58:45
Verstehe die Problematik nicht.
Selbsttriggerung über Timer-Substates geht doch jetzt schon.

Das selbsttriggernde Lauflicht aus Antwort#1 geht z.B. so:
define LL DOIF ([LL:?start] or [LL] eq "cmd_3")\
    ()\
    ()\
DOELSEIF ([LL] eq "cmd_1") \
    ()\
    ()\
DOELSEIF ([LL] eq "cmd_2")\
    ()\
    ()\
DOELSEIF ([LL:?stop])\

attr LL wait 0,10:0,10:0,10


Starten mit
trigger LL start
Stoppen mit:
trigger LL stop

Wenn man im Ausführungsteil einer ordentlich programmierten FSM auf den Status einwirken will, kann man das doch auch nur, indem man eine definierte Übergangsbedingung setzt, die beim nächsten Durchlauf abgefragt wird.

Bei event-gesteuerten Maschinen kann das zwangsläufig nur zeitverzögert geschehen.

Gruß
cruz

ja, ich habe zuvor extra mit viel Gehirnschmalz einen Mechanismus eingebaut, um Rekursionen im Modul zu verhindern, was nicht unwichtig ist, da sich user bereits indirekt Loop programmiert haben. Das Blockieren der Rekursion führt natürlich jetzt dazu, dass man beim Setzen des Status im Modul, das Modul nicht sofort angetriggert werden kann, bevor die vorherige Abarbeitung beendet ist - ich denke das muss auch so bleiben. Deine vorgeschlagene Lösung funktioniert zumindest, ansonsten werden wohl externe Events zu Zustandsübergängen führen und dann reichen einfache Abfragen des eigenen Zustands aus.

Gruß

Damian
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Zitat von: Ellert am 12 Februar 2016, 11:18:03
Das DOIF bleibt nach dem [start] trigger bei cmd_1 stehen. Hier solllte der Status triggern.
di ([start] or [di] eq "cmd_3") ()
DOELSEIF ([di] eq "cmd_1") ()
DOELSEIF ([di] eq "cmd_2") ()

wait 10:10:10


Es ist ja auch logisch, dass es dort stehen bleibt, da beim zweiten Durchlauf [start] immer noch wahr ist. Du musst zum Starten am besten ein Event abfragen: [di:"start"], das wäre beim zweiten Durchlauf nicht mehr wahr und schon funktioniert die Sache, wie programmiert.

Gruß

Damian
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

crusader

Zitat von: Damian am 12 Februar 2016, 23:35:55
..., da sich user bereits indirekt Loop programmiert haben.

Ja, ich zum Beispiel.

Hab' mich zuerst gewundert, warum das DOIF nicht triggert. Als mir dann klar wurde, dass irgendein Mechanismus die Rückkopplung verhindert, war ich aber doch ziemlich froh drum.
Man glaubt ja gar nicht, wie fix so'n kleiner Prozessor heutzutage kilometerlange Logfiles 'rausschiebt  :D .


Ellert

#23
Zitat von: Damian am 13 Februar 2016, 00:24:24
Es ist ja auch logisch, dass es dort stehen bleibt, da beim zweiten Durchlauf [start] immer noch wahr ist. Du musst zum Starten am besten ein Event abfragen: [di:"start"], das wäre beim zweiten Durchlauf nicht mehr wahr und schon funktioniert die Sache, wie programmiert.

Gruß

Damian
Ich habe immer gedacht alle Loops sind unterbunden und deshalb triggert [<doifname>] eq "cmd_<state>" nicht.

define di DOIF (["^start$"] or [di] eq "cmd_3") (({Log 1,"cmd_1"}))
DOELSEIF ([di] eq "cmd_1") (({Log 1,"cmd_2"}))
DOELSEIF ([di] eq "cmd_2") (({Log 1,"cmd_3"}))

wait 10:10:10


Hier habe ich ein Startereignis eingebaut, das DOIF läuft trotzdem nicht weiter, es bleibt beim 1. "cmd_1" stehen.
2016.02.13 08:39:54 1: cmd_1
Das hätte ich auch erwartet, wenn Du nicht geschrieben hättest: "Die Selbsttriggerung in Verbindung mit wait ging immer schon."

Die Aussage habe ich so verstanden, dass nach Ablauf des Waittimers im 1. Bedingungszweig, dann die Bedingung im 2. Bedingungszweig [di] eq "cmd_1" triggert, usw.

Und wenn kein wait angegeben ist, dann würde [di] eq "cmd_1" nicht triggern.

Habe ich das richtig verstanden?

Edit: Es funktioniert, so wie Du geschrieben hast, danke für die Geduld.

fiedel

Wäre es eigentlich innerhalb einer solchen FSM mit DOIF auch möglich gleich die Fehlerüberwachung mit einzubauen? Konventionell muss ich dafür immer externe "at" starten.
DOIF hat das "at" ja schon drin und könnte vielleicht sowas: ?

- starte Schritt 1 + starte Überwachungszeit 1 + führe Befehl aus (z.B. Motor 1 start) -> warte auf Weiterschaltbedingung 1
- wenn Ablauf Überwachungszeit -> Fehler 1 erkannt -> führe Befehl aus (z.B. Motor stop + Signal + Nachricht 1)
- wenn Weiterschaltbedingung vor Ablauf Überwachungszeit -> stoppe Überwachungszeit 1 + schalte weiter zu Schritt 2 +
   starte Überwachungszeit 2 + führe Befehl aus (z.B. Motor 2 start) -> warte auf Weiterschaltbedingung 2 usw.
... also das was man üblicherweise z.B. mit einer SPS macht.

Gruß
Frank
FeatureLevel: 6.1 auf Wyse N03D ; Deb. 11 ; Perl: v5.14.2 ; IO: HM-MOD-RPI-PCB + VCCU|CUL 868 V 1.66|LinkUSBi |TEK603
HM: SEC-SCO|SCI-3-FM|LC-SW4-PCB|ES-PMSW1-PL|RC-4-2|SEN-MDIR-O|SEC-WDS-2
CUL: HMS100TF|FS20 S4A-2 ; OWDevice: DS18S20|DS2401|DS2406|DS2423

Damian

Zitat von: fiedel am 13 Februar 2016, 09:56:59
Wäre es eigentlich innerhalb einer solchen FSM mit DOIF auch möglich gleich die Fehlerüberwachung mit einzubauen? Konventionell muss ich dafür immer externe "at" starten.
DOIF hat das "at" ja schon drin und könnte vielleicht sowas: ?

- starte Schritt 1 + starte Überwachungszeit 1 + führe Befehl aus (z.B. Motor 1 start) -> warte auf Weiterschaltbedingung 1
- wenn Ablauf Überwachungszeit -> Fehler 1 erkannt -> führe Befehl aus (z.B. Motor stop + Signal + Nachricht 1)
- wenn Weiterschaltbedingung vor Ablauf Überwachungszeit -> stoppe Überwachungszeit 1 + schalte weiter zu Schritt 2 +
   starte Überwachungszeit 2 + führe Befehl aus (z.B. Motor 2 start) -> warte auf Weiterschaltbedingung 2 usw.
... also das was man üblicherweise z.B. mit einer SPS macht.

Gruß
Frank

Vieles davon sieht man in den Readings des Moduls. Irgendwann baue ich noch ein ausführlicheres Logging dieser Ereignisse steuerbar über verbose. 

Gruß

Damian
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Zitat von: Ellert am 13 Februar 2016, 09:10:42
Ich habe immer gedacht alle Loops sind unterbunden und deshalb triggert [<doifname>] eq "cmd_<state>" nicht.

Man kann sagen: wenn eine Aktion im Modul indirekt (verzögert) über den internen Sleeptimer stattfindet (entspricht einer Verzögerung durch wait), so kann das Modul selbst drauf reagieren.

Gruß

Damian
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Loredo

#27
Ah, so nennt man das.
Ggf. hat sich meine Nachfrage nach einer Variablen $SELF hier damit auch erledigt? Wir meinen wohl das gleiche. Allerdings kombiniere ich den Selbststatus zu 99% mit cmdState. $SELF sollte dann wohl tatsächlich den cmdState enthalten, während deine vereinfachte Schreibweise ala $1 o.ä. dann unabhängig von cmdState sein sollte. Also vielleicht muss man das beides als Ergänzung sehen?
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER

Damian

Zitat von: Loredo am 14 Februar 2016, 14:45:32
Ah, so nennt man das.
Ggf. hat sich meine Nachfrage nach einer Variablen $SELF hier damit auch erledigt? Wir meinen wohl das gleiche. Allerdings kombiniere ich den Selbststatus zu 99% mit cmdState. $SELF sollte dann wohl tatsächlich den cmdState enthalten, während deine vereinfachte Schreibweise ala $1 o.ä. dann unabhängig von cmdState sein sollte. Also vielleicht muss man das beides als Ergänzung sehen?

Dann schauen wir mal, worauf man sich hier einigt.

Gruß

Damian
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

crusader

Zitat von: Loredo am 14 Februar 2016, 14:45:32
...
$SELF sollte dann wohl tatsächlich den cmdState enthalten,
...

Nach meinem Vorschlag würde $SELF (oder $THIS oder $NAME ) den devicename beinhalten. Damit liessen sich ganz unabhängig von der FSM-Anwendung Variablen im DOIF-Device speichern oder Attribute abrufen, ohne dass der aktuelle Name explizit angegeben (und bei rename umgeschrieben) werden muss.
Insofern wäre es ein Pendant zu '$name' in userReadings.

Der Ausdruck [$self] beinhaltet dann natürlich die state-Variable.

Im Übrigen bringt die Verwendung des cmdstate als FSM-State-Variable einige Nachteile mit sich:

1. Schwer lesbarer Code (durchnummerierte states statt selbstdokumentierende state-Namen)
2. Bei states mit mehreren Eingängen müssen alle transitions in eine DOELSEIF-Bedingung geschrieben werden. Dadurch entsteht ein unhandliches 'and/or' Konstrukt.
3. States können nicht gleichzeitig von timeout- und conditional transitions erreicht werden.
4. Unterscheidung von 'transition action' und 'state entry action' nicht möglich.

Eine übersichtliche FSM- Realisierung würde ich mir eher als Aneinanderreihung solcher Statements vorstellen:

...
DOELSEIF ([?$self:FS] eq "mystateA" and (<my transition-event X>))
   (<my transition-action 1>)
   ({nextFS("$SELF","<my nextstateB>"})
...


in der externen Perl-Routine wird dann die entry-action ausgeführt und die FS-Variable gesetzt.

Damit liesse sich ein FSM-Entwurf (auf Papier oder per Grafik-Tool) 1:1 in DEFINE-code umsetzen (und die ein oder andere FSM mit state-Sackgasse würde sich vermeiden lassen  ;) ).