DOIF neue Features: Generalisierung, $DEVICE, $EVENT, Attribut notexist

Begonnen von Damian, 28 Dezember 2015, 22:06:42

Vorheriges Thema - Nächstes Thema

CoolTux

Zitat von: JoeALLb am 03 Februar 2016, 09:25:08
Wenn wir schon am träumen sind... :)
Wir wäre es mit einer (einfachen) Verschachtelung von IFs ,ähnlich zu

(set lg_light on [DOIFsub $EVENT eq "TEMPL"])



oder gar

  DOIF ([winter])
    (set desired-temp 18 )
    CASE ([light] eq "on")
       (set xyy)
    CASE ([garage] eq "offen")
       (set xyyZZ)
    CASEEND
  DOELSEIF ([sommer])
    (set desired-temp off )


Zum Hintergrund:
Ich habe in ein großes DOIF mit sehr vielen (set ...) Einträgen, manche haben aber bestimmte Bedingungen wie Lichteinfall, etc.
Mit reinen DOELSEIF ist das schwierig, mit notify auch ;-). Das alles in eigene DOIFS zu ziehen wird unübersichtlich...

Aber wie gesagt, nur ein Traum... vielen Dank für die tolle Arbeit!

Hallo,

Für weitergehende Verarbeitungen in Form von Abfragen kannst Du ja eine 99_myUtils anlegen. Nur so eine Idee.


Grüße

Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

Reinerlein

Hallo Damian,

ich bin gerade dabei mit der neuen Version eine Fenster-offen-Meldung zu basteln.
Das geht auch gut los. Allerdings wollte ich nicht immer die gleiche Meldung versenden, sondern je nach Relation von Innen- zu Außentemperatur verschiedene (im Sommer ist ein offenes Fenster nur beim Verlassen des Hauses wichtig, im Winter wird es halt auch kalt im Raum).

Deshalb brauche ich z.B. folgende Bedingung (altes Format für einen festen Raum/Fensterkontakt, ist jetzt nur exemplarisch eine Bedingung des ganzen Konstrukts):
[code]
([heizung_Schlafzimmer_FK_Links] eq open and [aussen_Temperatur:temperature] >= [heizung_Schlafzimmer_WT:desiredTemperatureWeekprofile]) ((
  set telegram message

Damian

Zitat von: Reinerlein am 04 Februar 2016, 14:32:07
Hallo Damian,

ich bin gerade dabei mit der neuen Version eine Fenster-offen-Meldung zu basteln.
Das geht auch gut los. Allerdings wollte ich nicht immer die gleiche Meldung versenden, sondern je nach Relation von Innen- zu Außentemperatur verschiedene (im Sommer ist ein offenes Fenster nur beim Verlassen des Hauses wichtig, im Winter wird es halt auch kalt im Raum).

Deshalb brauche ich z.B. folgende Bedingung (altes Format für einen festen Raum/Fensterkontakt, ist jetzt nur exemplarisch eine Bedingung des ganzen Konstrukts):

([heizung_Schlafzimmer_FK_Links] eq open and [aussen_Temperatur:temperature] >= [heizung_Schlafzimmer_WT:desiredTemperatureWeekprofile]) ((
  set telegram message


Zuerst würde ich mir ein Konzept für die Namensgebung machen: z. B. Kontakt: "Heizung_Schlafzimmer" und  WT´s "WT_<Kontaktname>" hier dann "WT_Heizung_Schlafzimmer", ansonsten musst du irgendwo eine Abbildung vom Kontakt zum WT über readings, dummys etc. machen. Dann einfach definieren:

(["^Heizung_:open"] and [aussen_Temperatur:temperature] >= [^WT_$DEVICE:desiredTemperatureWeekprofile]) (set telegram message Fenster $DEVICE offen)

Gruß

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

Reinerlein

Hi Damian,

die ganzen Komponenten folgen schon einer Namenskonvention, nur andersherum, sprich die Komponenten werden hinten beschrieben, und die Räume vorne nach dem Schlüsselwort "heizung_".
Da das an vielen anderen Stellen schon berücksichtigt wird, kann ich das jetzt nicht mehr verändern...

Aber du erwähntest die Möglichkeit der Verbindung über ein Reading o.ä..
Wenn ich also im Fensterkontakt ein Reading hinterlegen würde, welches auf das Wandthermostat verweist. z.B.:

setreading heizung_Schlafzimmer_FK_Links associatedWT heizung_Schlafzimmer_WT
wie würde ich dass dann in der Bedingung des DOIF verwenden können?

Danke für deine Hilfe...

Grüße
Reiner

Damian

Zitat von: Reinerlein am 04 Februar 2016, 15:05:07
Hi Damian,

die ganzen Komponenten folgen schon einer Namenskonvention, nur andersherum, sprich die Komponenten werden hinten beschrieben, und die Räume vorne nach dem Schlüsselwort "heizung_".
Da das an vielen anderen Stellen schon berücksichtigt wird, kann ich das jetzt nicht mehr verändern...

Aber du erwähntest die Möglichkeit der Verbindung über ein Reading o.ä..
Wenn ich also im Fensterkontakt ein Reading hinterlegen würde, welches auf das Wandthermostat verweist. z.B.:

setreading heizung_Schlafzimmer_FK_Links associatedWT heizung_Schlafzimmer_WT
wie würde ich dass dann in der Bedingung des DOIF verwenden können?

Danke für deine Hilfe...

Grüße
Reiner

Ich sehe gerade, dass mein Ansatz vermutlich deinen Anforderungen nicht entsprechen würde, weil du ja insb. eine Meldung haben willst, wenn das Fenster bereits geöffnet ist und dann die Temperaturdifferenz zuschlägt. Das ist dann nicht mehr so einfach, weil der Trigger die Aussentemperatur ist und nicht das Fenster. Daher ist $DEVICE-Abfrage nicht möglich, weil $DEVICE der aussen_temp-Sensor ist. Da fällt mir auf Anhieb keine generalisierte Lösung ein. Vielleicht hat ein anderer DOIF-Experte einen Generalisierungsvorschlag parat.

Gruß

Damian

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

Reinerlein

Hi Damian,

vielleicht könnte die Variable $device nur bei variablen Deviceangaben mit "" gefüllt werden.
Oder es gibt mehrere Device-Variablen, für jede Deviceangabe in der Bedingung eine (irgendwie durchnummeriert oder so)...

Letztendlich, wenn man seine Notifys großflächig durch Doifs ersetzen möchte, wird man öfter an so etwas geraten:
Man stellt Bedingungen aus mehreren Deviceinformationen zusammen, die gemeinsam in einem Resultat (bzw. einem Zustand) enden. Das ist ja auch genau die Stärke und Übersichtlichkeit von Doif...
In einem Notify baut man das ja zu dem Trigger selbst in den Code als zusätzliche If-Bedingung ein...

Momentan hat die Variable $device eher die Bedeutung von $triggerdevice. In meinem Fall bräuchte ich aber das Device der ersten Teilbedingung (die ja variabel ist). Hier wäre es egal, warum oder von wem eine Bedingung getriggert wurde, sondern nur der (Gesamt-)Zustand als solches (im Sinne einer zutreffenden Summe aller Bedingungen der Doif-Zeile) ist wichtig.
In meinem jetzigen Fall wären die anderen Devices egal, kann aber natürlich in einem anderen Fall auch mal anders sein...

Momentan wäre es mir noch nichtmal wichtig, dass nachträglich durch die gesunkene Temperatur getriggert würde... Da reicht mir die Aussage zum Zeitpunkt der Fensteröffnung.
Könnte man das denn jetzt schon erreichen?

Danke schonmal, trotz der komplizierten Lage :)

Grüße
Reiner

Damian

Zitat von: Reinerlein am 04 Februar 2016, 16:41:05
In meinem Fall bräuchte ich aber das Device der ersten Teilbedingung (die ja variabel ist).
Das ist aber nicht bekannt, wenn der Trigger von einem anderen Device kommt.

Ich habe mich lange gewährt diese Generalisierung a la notify einzubauen. Es gibt ja auch nicht umsonst keine Bezeichner (Variablen etc.) in höheren Sprachen, die man mit * verallgemeinern könnte.

Alternative mit angesprochener Einschränkung:

(["^Heizung_:open"] and [?aussen_Temperatur:temperature] >= [$DEVICE:associatedWT]) (set telegram message Fenster $DEVICE offen)


Das Reading associatedWT müsste immer das aktuelle desiredTemperatureWeekprofile haben. Das könnte man mit einem anderen DOIF aktualisieren.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Reinerlein

Hi Damian,

ah... ich dachte man könnte als Reading einen Verweis auf das andere Device angeben (deswegen ja auch der Name associatedWT)...

hmmm... da muss ich jetzt mal in mich gehen, und eine Entscheidung treffen, ob ich für jeden Fensterkontakt doch ein konkretes Doif anlege, oder ob ich es doch über ein Notify löse... beides hat da Vor- und Nachteile...

Trotzdem Danke für deine Mühen.

Noch zu den *-Variablen: Natürlich gibt es sowas in höheren Programmiersprachen. Mittels Klassenstrukturen (bzw. deren Objekten zur Laufzeit) und Referenzen kannst du natürlich genau sowas hinbekommen.
Deswegen hatte ich mich schon gewundert, wie du die Generalisierung ohne Objekte (die es in Fhem ja nicht gibt) hingebogen hast. Dafür müsstest du ja schließlich bei jedem Event die entsprechende Ausprägung des damaligen kompletten Doif wiederherstellen können, um an der Stelle weitermachen zu können, wo das letzte mal bei der Eventausführung aufgehört wurde.
Man könnte natürlich ein Reading im Doif ablegen, welches für jedes gefundene Device den kompletten Doif-Zustand (die alten Werte bei den Bedingungen und den Cmd-Zustand) serialisiert ablegt. Das wird aber extrem unübersichtlich und sollte man wohl eher lassen :)

Oder man baut sowas wie einen Laufzeit-DOIF-Generator: Wenn man ein generisches Doif mit Platzhalter definiert hat, und es kommt ein Event, was passt, erzeugt man flugs eine temporäre Kopie des generischen DOIF bei dem alle erkannten Platzhalter (die ja auf dieses Event passen müssten) konkretisiert werden, sodass da wieder ein Standard-DOIF existiert, welches genau für dieses Event passt, und nun erstmal lebt und seine Arbeit macht :)

Sorry für diesen Erguss... ich finde das Modul großartig und finde es immer Schade, wenn man dann an Grenzen stößt...

Grüße
Reiner

Damian

Zitat von: Reinerlein am 04 Februar 2016, 21:59:32
Hi Damian,

ah... ich dachte man könnte als Reading einen Verweis auf das andere Device angeben (deswegen ja auch der Name associatedWT)...

[[[[[..]]]]] geht noch nicht.

Zitat
Noch zu den *-Variablen: Natürlich gibt es sowas in höheren Programmiersprachen. Mittels Klassenstrukturen (bzw. deren Objekten zur Laufzeit) und Referenzen kannst du natürlich genau sowas hinbekommen.
Deswegen hatte ich mich schon gewundert, wie du die Generalisierung ohne Objekte (die es in Fhem ja nicht gibt) hingebogen hast. Dafür müsstest du ja schließlich bei jedem Event die entsprechende Ausprägung des damaligen kompletten Doif wiederherstellen können, um an der Stelle weitermachen zu können, wo das letzte mal bei der Eventausführung aufgehört wurde.
Man könnte natürlich ein Reading im Doif ablegen, welches für jedes gefundene Device den kompletten Doif-Zustand (die alten Werte bei den Bedingungen und den Cmd-Zustand) serialisiert ablegt. Das wird aber extrem unübersichtlich und sollte man wohl eher lassen :)

Oder man baut sowas wie einen Laufzeit-DOIF-Generator: Wenn man ein generisches Doif mit Platzhalter definiert hat, und es kommt ein Event, was passt, erzeugt man flugs eine temporäre Kopie des generischen DOIF bei dem alle erkannten Platzhalter (die ja auf dieses Event passen müssten) konkretisiert werden, sodass da wieder ein Standard-DOIF existiert, welches genau für dieses Event passt, und nun erstmal lebt und seine Arbeit macht :)

Tja, FHEM ist nun mal nicht objektorientiert, sondern prozedural programmiert, daher muss man schon in dieser Welt bleiben.  Der Begriff Generalisierung ist sicherlich hier nicht ganz richtig und stand entfremdet für die Möglichkeit verschiedene Devices mit einer Abfrage zu erschlagen, allerdings mit den Einschränkungen, die sich aus der Welt ohne dynamische Objekte ergeben.

Also schauen wir mal, was sich noch mit vertretbaren Programmieraufwand an Möglichkeiten im Sinne der "Generalisierung" für den FHEM-User ergibt.

Gruß

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

Reinerlein

Hi Damian,

ich habe mich jetzt für einen eigenen Generator auf Basis einer Kopiervorlage (ein Deaktivierter DOIF mit Platzhaltern, die beim Erzeugen des Ziel-DOIFs ersetzt werden) entschieden.

Nun habe ich mein komplettes DOIF fertig, aber das Problem, dass es nicht auslöst. Wenn ich das Fenster öffne, steht für eine kurze Weile im Reading "wait_timer" der korrekte Auslösezeitpunkt (verzögert), mit dem korrekten Zielzustand (in dem Fall unten wurde auf cmd2 verwiesen).
Dann aber verschwindet dieses Reading "wait_timer" vor Ablauf, und er ändert auch nicht den Zustand des DOIFs, obwohl die Bedingungen immer noch stimmen (wie man am Listing bei den erkannten Werten in den Readings auch sehen kann).
Dann wird der "wait_timer" irgendwann wieder gesetzt (das war in diesem Beispiel also zwischen normaler Anzeige des DOIFs und dem Anzeigen per "list"), startet aber natürlich wieder von vorne.

Das geht so weiter, ohne das jemals ein anderer Zustand erreicht wird . Was für eine Offen-Meldung natürlich nicht so praktisch ist :)
[code]
Internals:
   CFGFN
   DEF        ([heizung_Schlafzimmer_FK_Links] eq "opened" and [aussen_Temperatur:temperature] >= [heizung_Schlafzimmer_WT:desiredTemperatureWeekprofile]) ((
  set telegram message

Damian

Zitat von: Reinerlein am 06 Februar 2016, 11:36:37
Hi Damian,

ich habe mich jetzt für einen eigenen Generator auf Basis einer Kopiervorlage (ein Deaktivierter DOIF mit Platzhaltern, die beim Erzeugen des Ziel-DOIFs ersetzt werden) entschieden.

Nun habe ich mein komplettes DOIF fertig, aber das Problem, dass es nicht auslöst. Wenn ich das Fenster öffne, steht für eine kurze Weile im Reading "wait_timer" der korrekte Auslösezeitpunkt (verzögert), mit dem korrekten Zielzustand (in dem Fall unten wurde auf cmd2 verwiesen).
Dann aber verschwindet dieses Reading "wait_timer" vor Ablauf, und er ändert auch nicht den Zustand des DOIFs, obwohl die Bedingungen immer noch stimmen (wie man am Listing bei den erkannten Werten in den Readings auch sehen kann).
Dann wird der "wait_timer" irgendwann wieder gesetzt (das war in diesem Beispiel also zwischen normaler Anzeige des DOIFs und dem Anzeigen per "list"), startet aber natürlich wieder von vorne.

Das geht so weiter, ohne das jemals ein anderer Zustand erreicht wird . Was für eine Offen-Meldung natürlich nicht so praktisch ist :)

Internals:
   CFGFN
   DEF        ([heizung_Schlafzimmer_FK_Links] eq "opened" and [aussen_Temperatur:temperature] >= [heizung_Schlafzimmer_WT:desiredTemperatureWeekprofile]) ((
  set telegram message


Der wait_timer wird immer dann gelöscht, wenn während der Wartezeit ein Trigger kommt, aufgrund dessen wieder  der ursprünglicher Zustand erreicht wird.

Bsp.:

aktueller Zustand: cmd_1
  Trigger (Bedingung für cmd_2 erfüllt) -> wait_timer für cmd_2
  Trigger während der Wartezeit (Bedingung für cmd_1 erfüllt) wait_timer gelöscht, da man ja noch in cmd_1 ist.

Gruß

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

crusader

Hallo Damian,

ich habe die aktuelle DOIF-Version 2016-02-03 mal testweise aktiviert. Laut Beschreibung sollte ja die alte Event-Notation [<device>:?<event>] weiterhin verwendet werden können.

Bei meiner Trigger-Bedingung  'DOIF ([S0count:?Counter])' erhalte ich nun aber folgende Fehlermeldung:

2016-02-06 20:52:09 DOIF S0proc error: perl error in condition: EventDoIf('S0count',$hash->{helper}{triggerDev},$hash->{helper}{triggerEvents},'Counter'): Can't use string ("S0count") as a HASH ref while "strict refs" in use at ./FHEM/98_DOIF.pm line 141,  line 172.


Reinerlein

Hallo Damian,

das ist mir klar. Deshalb verwendet man ja ein DOIF. Nur hat sich bei mir nichts an den Bedingungen (bzw. den Werten dazu) geändert. Nach den Werten der Readings und des States müsste er in den Zustand 2 umschalten wollen. Er will aber in Zustand 4 bleiben.
Die Werte sind ja im DOIF-Listing zu erkennen, diese verändern sich nicht so stark, dass ein anderer Zustand eintreten müsste.

Es scheint so, als ob er irgendwie ein Event feststellt (der Temperatursensor liefert z.B. alle 5 Minuten einen neuen Wert und damit ein Event), und dabei den ursprünglichen Plan mit dem Umschalten auf Zustand 2 vergisst, obwohl alle Bedingungen noch passend dafür sind...
Um in Zustand 4 zu bleiben müsste ja der Fensterkontakt ein "closed" melden, dass passiert jedoch nachweislich nicht. Bei den anderen Werten könnten nur noch die Zustände 1 bis 3 eintreten. Er versucht aber kurz danach wieder in den Zustand 2 zu wechseln (nur dass dann der Timer halt neugestartet wurde), er stellt also die korrekten Werte fest...

Grüße
Reiner

Damian

Zitat von: Reinerlein am 06 Februar 2016, 21:55:19
Hallo Damian,

das ist mir klar. Deshalb verwendet man ja ein DOIF. Nur hat sich bei mir nichts an den Bedingungen (bzw. den Werten dazu) geändert. Nach den Werten der Readings und des States müsste er in den Zustand 2 umschalten wollen. Er will aber in Zustand 4 bleiben.
Die Werte sind ja im DOIF-Listing zu erkennen, diese verändern sich nicht so stark, dass ein anderer Zustand eintreten müsste.

Es scheint so, als ob er irgendwie ein Event feststellt (der Temperatursensor liefert z.B. alle 5 Minuten einen neuen Wert und damit ein Event), und dabei den ursprünglichen Plan mit dem Umschalten auf Zustand 2 vergisst, obwohl alle Bedingungen noch passend dafür sind...
Um in Zustand 4 zu bleiben müsste ja der Fensterkontakt ein "closed" melden, dass passiert jedoch nachweislich nicht. Bei den anderen Werten könnten nur noch die Zustände 1 bis 3 eintreten. Er versucht aber kurz danach wieder in den Zustand 2 zu wechseln (nur dass dann der Timer halt neugestartet wurde), er stellt also die korrekten Werte fest...

Grüße
Reiner

Poste mal list von dem Modul kurz nach dem wait_timer gelöscht wird.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Zitat von: crusader am 06 Februar 2016, 21:18:40
Hallo Damian,

ich habe die aktuelle DOIF-Version 2016-02-03 mal testweise aktiviert. Laut Beschreibung sollte ja die alte Event-Notation [<device>:?<event>] weiterhin verwendet werden können.

Bei meiner Trigger-Bedingung  'DOIF ([S0count:?Counter])' erhalte ich nun aber folgende Fehlermeldung:

2016-02-06 20:52:09 DOIF S0proc error: perl error in condition: EventDoIf('S0count',$hash->{helper}{triggerDev},$hash->{helper}{triggerEvents},'Counter'): Can't use string ("S0count") as a HASH ref while "strict refs" in use at ./FHEM/98_DOIF.pm line 141,  line 172.

Hast du das System für die neue Version neu gestartet?
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF