Richtige Anwendung von IF in DOIF

Begonnen von z0lt1, 21 September 2018, 22:19:49

Vorheriges Thema - Nächstes Thema

z0lt1

Hallo Zusammen,

ich habe mit eurer Hilfe schon meine gut funktionierende Eigenbau-Alarmanlage gebaut. Diese funktioniert auch super, soll aber nun ein wenig verfeinert werden. Konkret geht es um den Fall 2 in welchem die Alarmanlage aktiviert wird, und eine Ansage dazu gemacht wird. Es soll nun realisiert werden dass zwischen 22:00 - 08:00 Uhr die Ansage nur auf Lautstärke 10 ausgegeben wird, den Rest des Tages dann auf Lautstärke 50. Ich könnte natürlich noch mehr DOELSEIFs einfügen, aber ich bin mir sicher dass das auch eleganter geht. Ich habe was von "if" und "IF" gelesen, und würde um nicht nach Perl abzuschweifen das mit dem IF realisieren. Hier mein Modul:
Internals:
   DEF        ([Schalter.Alarmanlage] eq "on" and [haus_TuerKontakt.Alle] eq "open" and $cmd=~"0|4")
(set MyTTS volume 20,
set MyTTS tts "Achtung, es sind nicht alle Türen geschlossen, Alarmanlage wird in 60 Sekunden scharf geschaltet")
(set MyTTS tts "Alarmanlage ist nun scharf geschalten")

DOELSEIF ([Schalter.Alarmanlage] eq "on" and [haus_TuerKontakt.Alle] eq "closed" and $cmd=~"0|4")
(set MyTTS volume 20,
set MyTTS tts "Alarmanlage wird in 60 Sekunden scharf geschaltet")
(set MyTTS tts "Alarmanlage ist nun scharf geschalten")

DOELSEIF ([Schalter.Alarmanlage] eq "on" and [haus_TuerKontakt.Alle] eq "open" and $cmd=~"1.2|2.2")
(set MyTTS volume 50,
set MyTTS tts "Bitte Code eingeben um Alarmanlage zu entschärfen")

DOELSEIF ([Schalter.Alarmanlage] eq "off")
(set MyTTS volume 20,
set MyTTS tts "Alarmanlage wurde deaktiviert")
   MODEL      FHEM
   NAME       di_Alarmanlage
   NR         96
   NTFY_ORDER 50-di_Alarmanlage
   STATE      initialized
   TYPE       DOIF
   READINGS:
     2018-09-21 22:12:56   cmd             0
     2018-09-21 22:12:56   mode            enabled
     2018-07-23 21:16:37   my_state        on
     2018-09-21 22:12:56   state           initialized
   Regex:
   attr:
     cmdState:
       0:
         Kontakte offen Alarmanlage initialisiert
         Alarmanlage scharf
       1:
         Alarmanlage initialisiert
         Alarmanlage scharf
       2:
         Alarm ausgelöst
       3:
         Alarmanlage aus
     repeatcmd:
     wait:
       0:
         0
         60
       1:
         0
         60
     waitdel:
   condition:
     0          InternalDoIf($hash,'Schalter.Alarmanlage','STATE') eq "on" and InternalDoIf($hash,'haus_TuerKontakt.Alle','STATE') eq "open" and $cmd=~"0|4"
     1          InternalDoIf($hash,'Schalter.Alarmanlage','STATE') eq "on" and InternalDoIf($hash,'haus_TuerKontakt.Alle','STATE') eq "closed" and $cmd=~"0|4"
     2          InternalDoIf($hash,'Schalter.Alarmanlage','STATE') eq "on" and InternalDoIf($hash,'haus_TuerKontakt.Alle','STATE') eq "open" and $cmd=~"1.2|2.2"
     3          InternalDoIf($hash,'Schalter.Alarmanlage','STATE') eq "off"
   devices:
     0           Schalter.Alarmanlage haus_TuerKontakt.Alle
     1           Schalter.Alarmanlage haus_TuerKontakt.Alle
     2           Schalter.Alarmanlage haus_TuerKontakt.Alle
     3           Schalter.Alarmanlage
     all         Schalter.Alarmanlage haus_TuerKontakt.Alle
   do:
     0:
       0          set MyTTS volume 20, set MyTTS tts "Achtung, es sind nicht alle Türen geschlossen, Alarmanlage wird in 60 Sekunden scharf geschaltet"
       1          set MyTTS tts "Alarmanlage ist nun scharf geschalten"
     1:
       0          set MyTTS volume 20, set MyTTS tts "Alarmanlage wird in 60 Sekunden scharf geschaltet"
       1          set MyTTS tts "Alarmanlage ist nun scharf geschalten"
     2:
       0          set MyTTS volume 50, set MyTTS tts "Bitte Code eingeben um Alarmanlage zu entschärfen"
     3:
       0          set MyTTS volume 20, set MyTTS tts "Alarmanlage wurde deaktiviert"
     4:
   helper:
     globalinit 1
     last_timer 0
     sleeptimer -1
   internals:
     0           Schalter.Alarmanlage:STATE haus_TuerKontakt.Alle:STATE
     1           Schalter.Alarmanlage:STATE haus_TuerKontakt.Alle:STATE
     2           Schalter.Alarmanlage:STATE haus_TuerKontakt.Alle:STATE
     3           Schalter.Alarmanlage:STATE
     all         Schalter.Alarmanlage:STATE haus_TuerKontakt.Alle:STATE
   itimer:
   uiState:
   uiTable:
Attributes:
   cmdState   Kontakte offen Alarmanlage initialisiert,Alarmanlage scharf|Alarmanlage initialisiert,Alarmanlage scharf|Alarm ausgelöst|Alarmanlage aus
   do         always
   icon       building_security
   room       00_Kontrollzentrum
   wait       0,60:0,60


Falls es noch eine elegantere Variante gibt bin ich natürlich offen für Tipps und Vorschläge.

Damian

#1
Du bist inzwischen in einem Stadium, wo du nicht nur definieren, sondern auch schon programmieren willst. Dafür ist die flache DOIF Struktur im FHEM-Modus bedingt geeignet. Ich habe bei mir sehr viele DOIFs definiert, aber kaum welche, die größer als zehn Zeilen im FHEM-Modus haben. Wenn du mehr machen willst, dann würde ich dir diesen Modus empfehlen https://fhem.de/commandref_DE.html#DOIF_Perl_Modus

Edit: Die Syntax für das Definieren der Bedingungen ist in beiden Modi die selbe
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Ellert

Zitat von: z0lt1 am 21 September 2018, 22:19:49
... aber ich bin mir sicher dass das auch eleganter geht. ...
Falls es noch eine elegantere Variante gibt bin ich natürlich offen für Tipps und Vorschläge.

Nach welchen Kriterien bewertest Du Eleganz im Zusammenhang mit einer DOIF Gerätedefinition?

Damian

#3
Zitat von: Ellert am 22 September 2018, 00:22:09
Nach welchen Kriterien bewertest Du Eleganz im Zusammenhang mit einer DOIF Gerätedefinition?

Die Syntax ist an sich einfach:

DOIF (<Bedingung>) (IF (<Bedinung>) (fhem-Befehle))


Man fängt aber schnell an mit den Unzulänglichkeiten von FHEM zu kämpfen, z. B. IF(... wird schon nicht erkannt, weil FHEM unbedingt ein Leerzeichen hinter einem FHEM-Befehl braucht. Auf die Problematik: Wieviel Semikolons, in welcher FHEM-Tiefe man setzen muss, will ich erst gar nicht eingehen.
Schlimmer wird es, wenn man sich Dinge merken muss. Was macht der FHEM-Anwender - er benutzt Readings. Noch schlimmer wird es, wenn man mit Readings rechnen muss. Eine einfache Erhöhung um eins, ist schon ein setreading-Akt, der im Vergleich zu $i++ in Perl geschätzt Faktor tausend mehr Performance benötigt.

Dann kann man auch gleich:

DOIF {if (<Bedingung>) {if (<Bedinung>) {fhem"fhem-Befehle"}}

nehmen.

Hier muss man sich keiner Gedanken machen, wo ein Leerzeichen hinkommt und wo nicht. Und wie schon gesagt, die Syntax für die Bedingungen ist in beiden Fällen gleich.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Prof. Dr. Peter Henning

Und wenn man den Perl-Code dann auch noch in eine ordentliche Perl-Datei auslagert, ist es sogar noch wartbar ...

@z0lt1:Bitte korrekte Bezeichnungen verwenden - es handelt sich nicht um ein "Modul", sondern um die Definition eines DOIF-Devices.

Noch ein Tipp: TTS-Meldungen, die immer gleich bleiben, sollte man sich einmal als MP3-Datei holen. Ist sehr viel performanter.

Und noch ein Tipp: Das Modul 95_Alarm.pm macht das sehr viel einfacher.

LG

pah

Ellert

Zitat von: Prof. Dr. Peter Henning am 22 September 2018, 09:24:13
Noch ein Tipp: TTS-Meldungen, die immer gleich bleiben, sollte man sich einmal als MP3-Datei holen. Ist sehr viel performanter.
Die vom Modul Text2Speech erstellten MP3-Dateien werden wieder verwendet.

z0lt1

Ich danke euch schon mal für die Tips und Ratschläge ich werde mich morgen mal an die Arbeit machen und anschließend berichten.

z0lt1

Also ich habe das jetzt folgendermaßen gelöst:


...
DOELSEIF ([Schalter.Alarmanlage] eq "on" and [haus_TuerKontakt.Alle] eq "closed" and $cmd=~"0|4")
(IF ($hms gt "07:00" and $hms lt "20:00")
(set MyTTS volume 50)
ELSE
(set MyTTS volume 10),
set MyTTS tts "Alarmanlage wird in 60 Sekunden scharf geschaltet")
(set MyTTS tts "Alarmanlage ist nun scharf geschalten")
...


Zitat von: Prof. Dr. Peter Henning am 22 September 2018, 09:24:13
Und wenn man den Perl-Code dann auch noch in eine ordentliche Perl-Datei auslagert, ist es sogar noch wartbar ...

@z0lt1:Bitte korrekte Bezeichnungen verwenden - es handelt sich nicht um ein "Modul", sondern um die Definition eines DOIF-Devices.

Noch ein Tipp: TTS-Meldungen, die immer gleich bleiben, sollte man sich einmal als MP3-Datei holen. Ist sehr viel performanter.

Und noch ein Tipp: Das Modul 95_Alarm.pm macht das sehr viel einfacher.

Ich werde mir bzgl. den Bezeichnungen mühe geben ;-) Der Sommer war so lang und da vergisst man wieder alles wenn man es nicht mehr benutzt. Danke für den Tipp mit dem 95_Alarm.pm das werde ich mir anschauen

Zitat von: Ellert am 22 September 2018, 00:22:09
Nach welchen Kriterien bewertest Du Eleganz im Zusammenhang mit einer DOIF Gerätedefinition?
Elegant ist für mich ein Code der so aufgebaut ist, dass keine überschüssigen Zeilen drin stehen, also nach dem Prinzip, so viel wie nötig aber so wenig wie möglich.

Damian: Danke für die ganzen Tipps und Erklärungen. Ich habe mich immer mehr mit DOIF angefreundet und bin begeistert wie mächtig es ist. Nun versuche ich eben immer alles in ein Modul reinzustopfen um alles auf einen Blick zu haben. Wie du schon aber gesagt hast, wird es dann aber trotzdem schnell unübersichtlich, wo man hier die Grenze zieht muss ich noch rausfinden.

Noch eine Frage zum Abschluss: Kann ich in einem DOIF welches nach zutreffender Bedingung zwei Befehle ausführt also cmd1_1 und cmd1_2 NUR den Befehl cmd1_2 über repeatcmd wiederholen lassen (so wie es in wait möglich ist)?

Damian

Wenn´s funktioniert, dann ist alles gut.

repeatcmd kann nur ganze Sequenzen wiederholen.

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

Prof. Dr. Peter Henning

ZitatElegant ist für mich ein Code der so aufgebaut ist, dass keine überschüssigen Zeilen drin stehen, also nach dem Prinzip, so viel wie nötig aber so wenig wie möglich.
Pardon, das ist kein guter Programmierstil.

ZitatIch werde mir bzgl. den Bezeichnungen mühe geben
...
ZitatNun versuche ich eben immer alles in ein Modul reinzustopfen
::) ::)Nei-en. Es handelt sich nicht um ein Modul.

Wenn man Hilfe haben will, sollte man das eigene Handeln so beschreiben, dass die Helfenden etwas damit anfangen können.

LG

pah

Ellert

#10
Zitat von: z0lt1 am 24 September 2018, 18:01:24
Elegant ist für mich ein Code der so aufgebaut ist, dass keine überschüssigen Zeilen drin stehen, also nach dem Prinzip, so viel wie nötig aber so wenig wie möglich.
Du könntest alles in eine Zeile schreiben mehr ist nicht nötig und weniger ist nicht möglich ;)

Zum Thema Modul/Gerät: https://wiki.fhem.de/wiki/Ger%C3%A4t