Hallo,
keine Frage, DOIF ist mega. Und irgendwie denke ich jedes Mal, ich kann alles damit lösen, und meist fehlen am Ende ein paar Prozent zu meinem Glück...
was sicherlich an mein Unvermögen liegt ::)
Daher ohne viel Umschweife mal gefragt, wie kann ich das folgende Konstrukt elegant lösen
([TFK.Schuppeneingang.Sw.Dummy] eq "closed" and ([Alarmanlage] eq "on" or ([TFK.Eingang.Sw.04.Verschluss] eq "closed" and [TFK.Nebeneingang.Sw.04.Verschluss] eq "closed") or [TFK.Schuppeneingang.Sw.Dummy:state:sec]>3600 or ([isTwilight] eq "on" and [TFK.Schuppeneingang.Sw.Dummy:state:sec]>600))) (
{
fhem("set Keymatic.Schuppentuer:FILTER=r:lock!=locked lock")
}
)
Ich habe gelernt, anstelle von :sec muss ich wait nutzen, da :sec nicht selbst triggert. Allerdings habe ich dann 3-4 CMDs mit ein und demselben Ergebnis. In diesem Fall ist die Pflege der einen Zeile im Ausführungsteil kein Problem. Bei anderen, komplexeren DOIFs jedoch schon.
Geht es daher irgendwie besser / eleganter?
Kann ich z.B. eine Art globale Funktion über allen CMDs definieren, die ich innerhalb der CMDs aufrufe und bei der ich alle DOIF Vorteile nutzen kann?
Danke für ein wenig Input...
Ronny
Im DOIF FHEM-Modus kannst du eigene Perl-Routinen aufrufen, es gibt aber keine globalen DOIF-Attribute
Im DOIF-Perlmodus kannst du dagegen mit Templates arbeiten, damit kann man gleiche Abläufe mehrfach verwenden:
https://wiki.fhem.de/wiki/DOIF/Templates
das kann man bis zu Szenarien mit WEB-GUI ausbauen:
https://wiki.fhem.de/wiki/DOIF/Automatisierung
Danke für den Hint, das sieht schon vielversprechend aus. Und direkt kommen mir Fragen bei der Umsetzung:
Kann ich bei Template Bedingungen auch verschiedene "wait" Zeiträume hinterlegen?
Die Syntax aus dem Beispiel Zimmertemperaturen: {$1;; ## Zeitangabe\ erschließt sich mir nicht - warum muss hier eine geschweifte Klammer vorangestellt sein und nicht eine einfache?
So recht kriege ich mein Konstrukt oben nicht in ein Template überführt. Mal vereinfacht, wie setze ich hier folgende Bedingung:
([Tuer] eq "closed" and [Alarmanlage] eq "on" and [Tuer:state:sec]>3600)
Hier bringt ja ein pauschales wait nichts, da nach Aktivieren der Alarmanlage nicht 1h gewartet werden soll.
PS: Bietest du auch doif-Intensivkurse an? ;)
Die Vorgehensweise ist folgende:
1) Zuerst ein FHEM-DOIF in gleichwertiges Perl-DOIF übersetzen
2) Im zweiten Schritt variable Stellen durch Platzhalter ($1, $2 usw) ersetzen und ein Template definieren.
3) Template für verschiedene Devices (Szenarien) aufrufen
Als variable Stelle könnte z. B. hier das Device gelten:
([$1] eq "closed" and [Alarmanlage] eq "on" and [$1:state:sec]>3600)
Ich dachte, ich wäre schon bei Punkt 2. Deswegen verstehe ich noch nicht, wie aus DOIF ([05:00|8])() auf einmal DOIF DEF TPL ({[05:00|8]}) wird. Der Perlmodus erwartet doch {} in Kombination von "if" bei den Bedingungstriggern, oder nicht? (Und den Platzhalter sehe ich einfach als String-Ersetzungstext) Na ich durchwühle wohl nochmal die umfangreiche Doku..//Edit: In der Doku habe ich nun entdeckt, dass ich bestimmte Trigger ohne "if" mit ";" getrennt angeben kann.
ZitatAls variable Stelle könnte z. B. hier das Device gelten:
([$1] eq "closed" and [Alarmanlage] eq "on" and [$1:state:sec]>3600)
Aber dann triggert das CMD doch niemals nach der definierten Zeit?
Und unterschiedliche waits kann ich nicht nutzen bei den verschiedenen Platzhalten?
Ich will das gerne als DOIF umsetzen, brauche aber noch einige Schubse bitte..
Zitat von: FHEMAN am 15 Dezember 2020, 16:13:39
Ich dachte, ich wäre schon bei Punkt 2. Deswegen verstehe ich noch nicht, wie aus DOIF ([05:00|8])() auf einmal DOIF DEF TPL ({[05:00|8]}) wird. Der Perlmodus erwartet doch {} in Kombination von "if" bei den Bedingungstriggern, oder nicht? (Und den Platzhalter sehe ich einfach als String-Ersetzungstext) Na ich durchwühle wohl nochmal die umfangreiche Doku..
//Edit: In der Doku habe ich nun entdeckt, dass ich bestimmte Trigger ohne "if" mit ";" getrennt angeben kann.
Aber dann triggert das CMD doch niemals nach der definierten Zeit?
Und unterschiedliche waits kann ich nicht nutzen bei den verschiedenen Platzhalten?
Ich will das gerne als DOIF umsetzen, brauche aber noch einige Schubse bitte..
Es triggert auch sonst nicht nach einer bestimmten Zeit. Mit sec wird nur das Alter des Readings abgefragt.
DOIF im Perlmodus arbeitet weitgehend ohne Attribute, wait wird dort mit sec_Exec realisiert: https://fhem.de/commandref_DE.html#DOIF_set_Exec
Dort kann man ebenso mit Platzhaltern arbeiten, die verschiedene Verzögerungen darstellen.
Danke für den Hinweis zu set_Exec. Immer, wenn ich mit DOIF aufgeben möchte, kommt eine Lösung zum Vorschein. Ich habe den Aufruf oben jetzt folgendermaßen gelöst:
([TFK.Schuppeneingang.Sw.Dummy] eq "closed" and ([Alarmanlage] eq "on" or ["isTwilight"] or ([TFK.Eingang.Sw.04.Verschluss] eq "closed" and [TFK.Nebeneingang.Sw.04.Verschluss] eq "closed"))) (
{
my $timer = 0;
if ("[Alarmanlage]" ne "on") {
$timer = ("[isTwilight]" eq "on") ? "600" : "3600";
}
set_Exec("timer",$timer,'fhem("set Keymatic.Schuppentuer:FILTER=r:lock!=locked lock")','ReadingsVal("TFK.Schuppeneingang.Sw.Dummy","state","open") eq "closed"')
}
Sollte eine der Bedingungen im unwahr werden, wird der Timer gecancelt, richtig?
isTwilight nutze ich als Eventtrigger. Ich bin gespannt, ob es klappt heute Abend.
("[Alarmanlage]" ne "on") wird nicht funktionieren
dann schon eher:
([Alarmanlage] ne "on")
Alarmanlage wirkt dann aber triggernd
daher eher:
([?Alarmanlage] ne "on")
Am besten, wenn es nicht triggern soll, gleich mit
(ReadingsVal("Alarmanlage","state","") ne "on")
abfragen.
Das Gleiche gilt für "isTwilight"
Zitat von: Damian am 16 Dezember 2020, 15:01:18
("[Alarmanlage]" ne "on") wird nicht funktionieren
Ich habe das bisher verwendet, um ungültige Stringvergleiche zu vermeiden. Manchmal war die Variable laut Log leer (nicht ""). Aber er betrachtet alles in "" wohl als Regex.
del_Exec kann und muss ich nicht in DOELSE() aufrufen?
Zitat von: FHEMAN am 16 Dezember 2020, 19:38:09
Ich habe das bisher verwendet, um ungültige Stringvergleiche zu vermeiden. Manchmal war die Variable laut Log leer (nicht ""). Aber er betrachtet alles in "" wohl als Regex.
del_Exec kann und muss ich nicht in DOELSE() aufrufen?
del_Exec kannst du nicht in DOELSE () aufrufen, weil im Perlmodus kein DOELSE existiert ;)
Zitat von: FHEMAN am 16 Dezember 2020, 13:10:53
([TFK.Schuppeneingang.Sw.Dummy] eq "closed" and ([Alarmanlage] eq "on" or ["isTwilight"] or ([TFK.Eingang.Sw.04.Verschluss] eq "closed" and [TFK.Nebeneingang.Sw.04.Verschluss] eq "closed"))) (
{
my $timer = 0;
if ("[Alarmanlage]" ne "on") {
$timer = ("[isTwilight]" eq "on") ? "600" : "3600";
}
set_Exec("timer",$timer,'fhem("set Keymatic.Schuppentuer:FILTER=r:lock!=locked lock")','ReadingsVal("TFK.Schuppeneingang.Sw.Dummy","state","open") eq "closed"')
}
)
Mit dieser Konstruktion gibt es den Perl Fehler, dass set_Exec unbekannt ist.
Ich vermute, es liegt daran, dass der Bedingungsteil noch in DOIF Notation ist? Was ich gerne so beibehalten würde. Aber wie muss ich die () dann richtig setzen?
Zitat von: FHEMAN am 21 Dezember 2020, 16:49:53
Mit dieser Konstruktion gibt es den Perl Fehler, dass set_Exec unbekannt ist.
Ich vermute, es liegt daran, dass der Bedingungsteil noch in DOIF Notation ist? Was ich gerne so beibehalten würde. Aber wie muss ich die () dann richtig setzen?
klar, das ist ein DOIF im FHEM-Modus und nicht im Perl-Modus, nur dort funktioniert set_Exec. Siehe https://fhem.de/commandref_DE.html#DOIF_Perl_Modus
Der Perl-Modus fängt nicht mit ( an.
Boah, habe es nun umgebaut.. fühlt sich nun alles ganz anders an.. keine checkall etc. Funktionen mehr. DOELSE() ist dann sicherlich auch überflüssig geworden, oder gibt es ein else {{}}?
Wenigstens ist jetzt das eigentlich verwirrende Wort DOELSE weg ;)
Zitat von: FHEMAN am 21 Dezember 2020, 17:34:51
Boah, habe es nun umgebaut.. fühlt sich nun alles ganz anders an.. keine checkall etc. Funktionen mehr. DOELSE() ist dann sicherlich auch überflüssig geworden, oder gibt es ein else {{}}?
Wenigstens ist jetzt das eigentlich verwirrende Wort DOELSE weg ;)
Es gibt alles, was es in Perl gibt, insb. else, elsif usw. und so gut wie keine Attribute ;) - man muss etwas umdenken, dafür kann man besser "programmieren"
Ich kämpfe weiter.. Kannst Du mir das bitte näher erklären:
Zitat von: Damian am 16 Dezember 2020, 15:01:18
("[Alarmanlage]" ne "on") wird nicht funktionieren
dann schon eher:
([Alarmanlage] ne "on")
Ich erhalte bei Bedingungen in der Art
([Resident1:state] eq "off" or [Resident2:state] eq "off")
die Fehlermeldung
doif.Test: off eq "off" or off eq "off": Unknown command off, try help.
Für mich sieht das so aus, als würden da "" fehlen?
Immer ein komplettes list liefern, mit den Bruchstücken kann man nichts anfangen.
Zitat von: Damian am 28 Dezember 2020, 19:50:52
Immer ein komplettes list liefern, mit den Bruchstücken kann man nichts anfangen.
Hi Damian, hier das list:
Internals:
DEF ([Residents.R:state] eq "on" or [Residents.M:state] eq "on" or [Residents.C:state] eq "on" or [Residents.E:state] eq "on" or [Residents.Unbekannt:state] eq "on")(
{
my @Residents =("Residents.R","Residents.M","Residents.Unbekannt");
my $PresenceCount = 0;
my $PresenceResidents = "";
foreach my $Resident (@Residents) {
my $ResidentState = (Value($Resident) eq "on") ? "1" : "0";
my $ResidentShort = alias($Resident);
if (($ResidentShort ne "Unbekannt") && ($ResidentState eq "1")) {
$PresenceResidents .= " $ResidentShort";
$PresenceCount++;
}
fhem("setreading Anwesenheit:FILTER=r:$ResidentShort!=$ResidentState $ResidentShort $ResidentState");
}
if ($PresenceResidents eq "") {
$PresenceResidents = "0";
}
fhem("setreading Anwesenheit PresenceResidents $PresenceResidents");
fhem("setreading Anwesenheit:FILTER=r:PresenceCount!=$PresenceCount PresenceCount $PresenceCount");
fhem("set Anwesenheit:FILTER=STATE!=on on");
my $ResidentTrigger = ReadingsVal("doif.Anwesenheit","cmd_event",-1);
}
) DOELSE ([Residents.R:state] eq "off" or [Residents.M:state] eq "off" or [Residents.C:state] eq "off" or [Residents.E:state] eq "off" or [Residents.Unbekannt:state] eq "off")(
{
fhem("setreading Anwesenheit:FILTER=r:Unbekannt!=0 Unbekannt 0");
fhem("setreading Anwesenheit:FILTER=r:PresenceCount!=0 PresenceCount 0");
fhem("setreading Anwesenheit:FILTER=r:PresenceResidents!=0 PresenceResidents 0");
fhem("set Anwesenheit:FILTER=STATE!=off off");
}
)
FUUID 5f8c4fde-f33f-6078-ae31-c79ab2edfb5311e9
MODEL FHEM
NAME doif.Anwesenheit
NOTIFYDEV Residents.M,Residents.Unbekannt,Residents.R,Residents.E,Residents.C,global
NR 1003
NTFY_ORDER 50-doif.Anwesenheit
STATE cmd_1
TYPE DOIF
VERSION 23235 2020-11-25 22:42:28
READINGS:
2020-12-30 14:11:15 Device Residents.R
2020-12-30 14:11:15 cmd 1
2020-12-30 14:11:15 cmd_event Residents.R
2020-12-30 14:11:15 cmd_nr 1
2020-12-30 14:10:15 e_Residents.M_state on
2020-12-30 14:11:15 e_Residents.R_state on
2020-12-30 14:10:40 e_Residents.Unbekannt_state on
2020-12-28 17:02:10 mode enabled
2020-12-30 14:11:15 state cmd_1
Regex:
accu:
cond:
Residents.C:
0:
state ^Residents.C$:^state:
Residents.E:
0:
state ^Residents.E$:^state:
Residents.M:
0:
state ^Residents.M$:^state:
Residents.R:
0:
state ^Residents.R$:^state:
Residents.Unbekannt:
0:
state ^Residents.Unbekannt$:^state:
attr:
cmdState:
wait:
waitdel:
condition:
0 ::ReadingValDoIf($hash,'Residents.R','state') eq "on" or ::ReadingValDoIf($hash,'Residents.M','state') eq "on" or ::ReadingValDoIf($hash,'Residents.C','state') eq "on" or ::ReadingValDoIf($hash,'Residents.E','state') eq "on" or ::ReadingValDoIf($hash,'Residents.Unbekannt','state') eq "on"
do:
0:
0 { my @Residents =("Residents.R","Residents.M","Residents.Unbekannt"); my $PresenceCount = 0; my $PresenceResidents = ""; foreach my $Resident (@Residents) { my $ResidentState = (Value($Resident) eq "on") ? "1" : "0"; my $ResidentShort = alias($Resident); if (($ResidentShort ne "Unbekannt") && ($ResidentState eq "1")) { $PresenceResidents .= " $ResidentShort"; $PresenceCount++; } fhem("setreading Anwesenheit:FILTER=r:$ResidentShort!=$ResidentState $ResidentShort $ResidentState"); } if ($PresenceResidents eq "") { $PresenceResidents = "0"; } fhem("setreading Anwesenheit PresenceResidents $PresenceResidents"); fhem("setreading Anwesenheit:FILTER=r:PresenceCount!=$PresenceCount PresenceCount $PresenceCount"); fhem("set Anwesenheit:FILTER=STATE!=on on"); my $ResidentTrigger = ReadingsVal("doif.Anwesenheit","cmd_event",-1); }
1:
0 [Residents.R:state] eq "off" or [Residents.M:state] eq "off" or [Residents.C:state] eq "off" or [Residents.E:state] eq "off" or [Residents.Unbekannt:state] eq "off"
1 { fhem("setreading Anwesenheit:FILTER=r:Unbekannt!=0 Unbekannt 0"); fhem("setreading Anwesenheit:FILTER=r:PresenceCount!=0 PresenceCount 0"); fhem("setreading Anwesenheit:FILTER=r:PresenceResidents!=0 PresenceResidents 0"); fhem("set Anwesenheit:FILTER=STATE!=off off"); }
helper:
DEVFILTER ^global$|^Residents.M$|^Residents.Unbekannt$|^Residents.E$|^Residents.R$|^Residents.C$
NOTIFYDEV global|Residents.M|Residents.Unbekannt|Residents.E|Residents.R|Residents.C
event on
globalinit 1
last_timer 0
sleeptimer -1
timerdev Residents.R
timerevent on
triggerDev Residents.R
timerevents:
on
timereventsState:
state: on
triggerEvents:
on
triggerEventsState:
state: on
internals:
readings:
all Residents.R:state Residents.M:state Residents.C:state Residents.E:state Residents.Unbekannt:state
trigger:
uiState:
uiTable:
Attributes:
do always
DOELESE hat keine Bedingung, was du meinst ist wohl DOELSEIF
Argh, ist mir komplett entgangen, da ich die zweite Bedingungen erst später formuliert habe. Die Fehlermeldung ist jetzt weg, danke!