Hallo zusammen,
ich habe mein erstes DOIF auf den Perl Modus umgestellt und es klappt schon recht gut.
Im Fhem Modus hatte ich jedoch mit dem set cmd_* auch direkt ausgeführt, ohne dass die Bedinungen geprüft wurden.
Geht das auch im Perl Modus mit den Blöcken?
Was könnte ich in der if-Abfrage eintragen, damit ich weiß, dass der Block jetzt manuell ausgeführt werden soll?
VG
Christian
Internals:
CFGFN
DEF ################################################################################################################
## 1 Alle Standby Multimedia Geräte wieder einschalten
##
1_Media_Ein
{if (!([$SELF:state] eq "off") ## DOIF enabled
and [07:30] ) {
if (AttrVal("$SELF","verbose",0) >=3)
{Log 3, "$SELF cmd_1 : Standby Multimedia aus"};
CommandSet(undef, "shelly06 on 0");
} else {
if (AttrVal("$SELF","verbose",0) >=3)
{Log 3, "$SELF cmd_1 : Standby Multimedia es ist nicht 07:30"};
}
}
################################################################################################################
## 2 Alle Multimedia Geräte abschalten
##
2_Media_Aus
{if (!([$SELF:state] eq "off") ## DOIF enabled
and ([22:00-02:00] and [TV_Wz:state] eq "off")
or [02:01] ) {
if (AttrVal("$SELF","verbose",0) >=3)
{Log 3, "$SELF cmd_2 : Standby Multimedia Fernseher abschalten"};
CommandSet(undef, "TV_Wz poweroff");
set_Exec("Standby_timer",5,'Standby_aus()');
} else {
if (AttrVal("$SELF","verbose",0) >=3)
{Log 3, "$SELF cmd_1 : Standby Multimedia Bedingungen nicht erfüllt"};
} }
################################################################################################################
## 3 Definition von Sub Routinen
sub Standby_aus { ## Es soll verzögert aus geschaltet werden
if (AttrVal("$SELF","verbose",0) >=3)
{Log 3, "$SELF cmd_2 : Standby Multimedia aus"};
CommandSet(undef, "shelly06 off 0");
}
FUUID 613f4312-f33f-61a8-5bcb-91aaef86af7b663b
MODEL Perl
NAME Wohnzimmer_Standby
NOTIFYDEV Wohnzimmer_Standby,TV_Wz,global
NR 25990
NTFY_ORDER 50-Wohnzimmer_Standby_II
STATE initialized
TYPE DOIF
VERSION 24905 2021-09-01 18:35:54
Helper:
DBLOG:
cmd:
LogDB:
TIME 1631536635.09994
VALUE 0
mode:
LogDB:
TIME 1631535890.66114
VALUE enabled
state:
LogDB:
TIME 1631536635.09994
VALUE initialized
READINGS:
2021-09-13 16:11:40 mode enabled
2021-09-13 16:11:40 state initialized
2021-09-13 16:11:40 timer_01_c01 14.09.2021 07:30:00
2021-09-13 16:11:40 timer_02_c02 13.09.2021 22:00:00
2021-09-13 16:11:40 timer_03_c02 14.09.2021 02:00:00
2021-09-13 16:11:40 timer_04_c02 14.09.2021 02:01:00
Regex:
accu:
collect:
cond:
TV_Wz:
1:
state ^TV_Wz$:^state:
Wohnzimmer_Standby:
0:
state ^Wohnzimmer_Standby$:^state:
1:
state ^Wohnzimmer_Standby$:^state:
attr:
condition:
0 if (!(::ReadingValDoIf($hash,'Wohnzimmer_Standby','state') eq "off") and ::DOIF_time_once($hash,0,$wday) ) {
if (AttrVal("Wohnzimmer_Standby","verbose",0) >=3)
{Log 3, "Wohnzimmer_Standby cmd_1 : Standby Multimedia aus"};
CommandSet(undef, "shelly06 on 0");
} else {
if (AttrVal("Wohnzimmer_Standby","verbose",0) >=3)
{Log 3, "Wohnzimmer_Standby cmd_1 : Standby Multimedia es ist nicht 07:30"};
}
1 if (!(::ReadingValDoIf($hash,'Wohnzimmer_Standby','state') eq "off") and (::DOIF_time($hash,1,2,$wday,$hms) and ::ReadingValDoIf($hash,'TV_Wz','state') eq "off")
or ::DOIF_time_once($hash,3,$wday) ) {
if (AttrVal("Wohnzimmer_Standby","verbose",0) >=3)
{Log 3, "Wohnzimmer_Standby cmd_2 : Standby Multimedia Fernseher abschalten"};
CommandSet(undef, "TV_Wz poweroff");
set_Exec("Standby_timer",5,'Standby_aus()');
} else {
if (AttrVal("Wohnzimmer_Standby","verbose",0) >=3)
{Log 3, "Wohnzimmer_Standby cmd_1 : Standby Multimedia Bedingungen nicht erfüllt"};
}
2 if (AttrVal("Wohnzimmer_Standby","verbose",0) >=3)
{Log 3, "Wohnzimmer_Standby cmd_2 : Standby Multimedia aus"};
CommandSet(undef, "shelly06 off 0");
days:
helper:
DEVFILTER ^global$|^TV_Wz$|^Wohnzimmer_Standby$
NOTIFYDEV global|TV_Wz|Wohnzimmer_Standby
globalinit 1
last_timer 4
sleeptimer -1
interval:
1 -1
2 1
intervalfunc:
localtime:
0 1631597400
1 1631563200
2 1631577600
3 1631577660
perlblock:
0 1_Media_Ein
1 2_Media_Aus
2 block_03
readings:
all Wohnzimmer_Standby:state TV_Wz:state
realtime:
0 07:30:00
1 22:00:00
2 02:00:00
3 02:01:00
time:
0 07:30:00
1 22:00:00
2 02:00:00
3 02:01:00
timeCond:
0 0
1 1
2 1
3 1
timer:
0 0
1 0
2 0
3 0
timers:
0 0
1 1 2 3
triggertime:
1631563200:
localtime 1631563200
hash:
1631577600:
localtime 1631577600
hash:
1631577660:
localtime 1631577660
hash:
1631597400:
localtime 1631597400
hash:
uiState:
uiTable:
Attributes:
DbLogExclude .*
alias Wohnzimmer_Standby
comment Version 2021.09.13 15:00
group PV Eigenverbrauch-Steuerung
icon clock
room Strom->Photovoltaik
sortby 493
verbose 3
Im DOIF-Perlmodus wird bei einem Trigger ein ganzer Block an Perl per eval übergeben. Welcher Zweig ausgeführt wird und welcher nicht, wird aufgrund der if-Bedingungen vom Perlinterpreter entschieden. DOIF kümmert sich in dem Fall nicht um die logischer Auswertung der Zweige. Im Perlmodus kann man zwar per set ganze Blöcke zur Ausführung bringen, was dort aber passiert entscheidet der Perlinterpreter.
Übrigens CommandSet(undef, "shelly06 off 0") entspricht im Perlmodus set_fhem("shelly06 off 0")
set cmd_* sollte über CommandSet funktionieren und damit auch per set_fhem,
Falls etwas aber per set_fhem nicht geht, so sollte es auf jeden Fall per fhem "set ..." gehen, denn fhem"..." entspricht dem, was man über die Kommandozeile ausführt.
dein sub muss noch in einen subs-Block. In den Beispielen hat Damian den auch immer am Anfang geschrieben, kann sein, daß die Reihenfolge egal ist. Ich fang immer an mit
init {
...
}
subs {
sub abc {
...
}
sub def {
...
}
}
meinBlock1 {
...
}
...
Zitat von: Sany am 13 September 2021, 17:07:01
dein sub muss noch in einen subs-Block. In den Beispielen hat Damian den auch immer am Anfang geschrieben, kann sein, daß die Reihenfolge egal ist. Ich fang immer an mit
Okay, das sieht schöner aus und Block_3 ist dann auch verschwunden.
Vielen Dank
Das behebt natürlich nicht das gemeldete Problem :-)
Ich habe in den Blöcken jeweils einen else Zweig, der z.B. beim "set Wohnzimmer_Standby 1_Media_Ein" durchlaufen wird, da im if ein Statement fehlt, was beim set Aufruf direkt den if Zeig auslöst.
VG
Christian
Zitat von: Damian am 13 September 2021, 16:56:43
Im DOIF-Perlmodus wird bei einem Trigger ein ganzer Block an Perl per eval übergeben. Welcher Zweig ausgeführt wird und welcher nicht, wird aufgrund der if-Bedingungen vom Perlinterpreter entschieden. DOIF kümmert sich in dem Fall nicht um die logischer Auswertung der Zweige. Im Perlmodus kann man zwar per set ganze Blöcke zur Ausführung bringen, was dort aber passiert entscheidet der Perlinterpreter.
Okay, das hatte ich so auch bereits gelesen.
Gibt es denn eine interne Variable, die ich abfragen kann, um zu sehen das gerade ein bestimmter Block mit "set <Device> 1_Media_Ein" aufgerufen wird?
Erzeugt das eventuell auch einen Event, den ich verwendne kann?
Dann könnte ich das ja in die if Abfrage des Blocks mit einfügen.
VG
Christian
Zitat von: Damian am 13 September 2021, 16:56:43
Übrigens CommandSet(undef, "shelly06 off 0") entspricht im Perlmodus set_fhem("shelly06 off 0")
Das habe ich eingebaut, es spart einige Zeichen und sieht auch besser aus ;-)
Zitat
"set <Device> cmd_*" sollte über CommandSet funktionieren und damit auch per set_fhem,
Hmm, im Perlmodus ist ja aus cmd_* ein Block_* geworden und man kann sprechende Namen verwenden. Das mit den sprechenden Namen hatte ich schon mal angefragt, da war ich aber noch nicht bis zum Perl Mode vorgedrungen :-) Danke dafür.
Zitat von: ch.eick am 13 September 2021, 17:25:14
Okay, das hatte ich so auch bereits gelesen.
Gibt es denn eine interne Variable, die ich abfragen kann, um zu sehen das gerade ein bestimmter Block mit "set <Device> 1_Media_Ein" aufgerufen wird?
Erzeugt das eventuell auch einen Event, den ich verwendne kann?
Dann könnte ich das ja in die if Abfrage des Blocks mit einfügen.
VG
Christian
Du kannst doch an beliebiger Stelle im Code selbst etwas z. B. per set auslösen, was du wo anders auswerten kannst. Innerhalb des Moduls kannst du Devicevariablen beginnend mit $_ setzen und abfragen.
Zitat von: Damian am 13 September 2021, 17:34:59
Du kannst doch an beliebiger Stelle im Code selbst etwas z. B. per set auslösen, was du wo anders auswerten kannst. Innerhalb des Moduls kannst du Devicevariablen beginnend mit $_ setzen und abfragen.
Ich denke ich habe mich falsch ausgedrückt.
Wenn ich ein "set <Device> Block_1" aufrufe wurde bisher dieser Block ohne Prüfung der Bedingungen ausgeführt.
Wenn ich das jetzt mache werden alle Bedingungen überprüft und der Code wird nicht durchlaufen.
Nun suche ich eine Abfrage für das if, an der ich erkennen kann, das es nicht ein Event war sondern ein manueller Aufruf. In diesem fall kann ich im if eine "or" Abfrage machen und den Code dann doch durchlaufen. Ansonsten müsste es bei Zeit Abfragen genau diese Uhrzeit sein und ich könnte den Code nicht manuell verwenden.
So der manuelle Aufruf zum Testen sein oder wozu brauchst du den?
Zitat von: Damian am 13 September 2021, 18:16:42
So der manuelle Aufruf zum Testen sein oder wozu brauchst du den?
1. zum Testen
2. Um aus anderen FHEM Bereichen die Funktionalität des Blocks "manuell" auszuführen.
Dies wäre z.B. eine Situation, bei der ich den PV_Speicher in den Status smart_laden setzen möchte, ohne das die Bedingungen in dem DOIF Block erfüllt sind.
EDIT:
Ich denke das könnte ich auch mit dem uiTable und einer select Auswahl erreichen. Da wird ja vom verwendeten reading ein Event erzeugt, aud den man im DOIF Block reagieren kann.
Wenn man das DOIF allerdings mit einem set <Device> Block_1 aufruft hilt das natürlich auch nicht.
Zitat von: ch.eick am 13 September 2021, 18:23:39
1. zum Testen
2. Um aus anderen FHEM Bereichen die Funktionalität des Blocks "manuell" auszuführen.
Dies wäre z.B. eine Situation, bei der ich den PV_Speicher in den Status smart_laden setzen möchte, ohne das die Bedingungen in dem DOIF Block erfüllt sind.
EDIT:
Ich denke das könnte ich auch mit dem uiTable und einer select Auswahl erreichen. Da wird ja vom verwendeten reading ein Event erzeugt, aud den man im DOIF Block reagieren kann.
Wenn man das DOIF allerdings mit einem set <Device> Block_1 aufruft hilt das natürlich auch nicht.
Wenn du mit DOIF im Perlmodus arbeiten willst, dann würde ich dir empfehlen mehr programmtechnisch vorzugehen. Wenn man beim Programmieren eine bestimmte Funktionalität zusammenfassen, kapseln oder nur vom Rest separieren will, dann packt man diesen Code in eine eigene Routine (Perl-Funktion). In Perl sind das die subs. Diese kann man separat aufrufen oder in irgendwelchen if-Zweigen unterbringen oder sonst etwas damit tun. Sie besitzen zusätzlich, wie in jeder Programmiersprache üblich, Übergabeparameter, über die man das Verhalten von außen steuern kann. Diese Vorgehensweise ist flexibler als nur in DOIF-DOELSEIF-Zweigen zu denken.
Zitat von: Damian am 13 September 2021, 19:25:36
Wenn du mit DOIF im Perlmodus arbeiten willst, dann würde ich dir empfehlen mehr programmtechnisch vorzugehen. Wenn man beim Programmieren eine bestimmte Funktionalität zusammenfassen, kapseln oder nur vom Rest separieren will, dann packt man diesen Code in eine eigene Routine (Perl-Funktion). In Perl sind das die subs. Diese kann man separat aufrufen oder in irgendwelchen if-Zweigen unterbringen oder sonst etwas damit tun. Sie besitzen zusätzlich, wie in jeder Programmiersprache üblich, Übergabeparameter, über die man das Verhalten von außen steuern kann. Diese Vorgehensweise ist flexibler als nur in DOIF-DOELSEIF-Zweigen zu denken.
Okay, das ist mir geläufig, aber danke für den Tip.
Nun möchte ich jedoch zum Abschluss noch meine Lösung präsentieren.
1.) Es können mit uiTable aus einer Liste die gewünschten Blöcker ausgewählt werden und werden ohne die komplette if Prüfung durchlaufen.
2.) Beim aufruf aus dem FHEM mit "set <Device> cmd_*" werden die Blöcke ebenfalls ausgeführt.
Und den Tip von oben mit der sub habe ich auch noch eingearbeitet. Dadurch wird es einfach übersichtlicher.
Der Code der einzelnen Blöcke ist hierbei nur exemplarisch.
Somit kann man die Steckdose im FHEMWEB jetzt auch direkt aus/ein Schalten.
Wenn man den Block mit "set <Device> 1_1_Media_[Ein|Aus]" aufruft, wird die if Anweisung eventuell durch eine falsche Uhrzeit oder den Status vom Fernesher blockiert,
was durch die zusätzlichen "or" Zweige ausgehebelt wird. Das war es, was ich die ganze Zeit gesucht , aber eventuell falsch ausgedrückt, hatte.
Besonderen Dank an Damian für den unermüdlichen Support.
VG
Christian
RAW vom Device
defmod Wohnzimmer_Standby DOIF ################################################################################################################\
## 1 Alle Standby Multimedia Geräte wieder einschalten\
##\
1_Media_Ein\
{if (!([$SELF:state] eq "off") ## DOIF enabled\
and ( [07:30] ## ab 7:30 Uhr alle Multimedia Geräte einschalten\
or [$SELF:cmd_event] eq "set_cmd_1" ## Das reagiert auf den Aufruf mit "set <Device> cmd_*"\
or [$SELF:ui_command] eq "Standby Steckdose ein" )) { ## Hier wird das uiTable select ausgewärtet\
\
Standby_Steckdose("on");; ## beliebige Kommandos für diesen Block\
\
set_Reading("ui_command","---");; ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\
## kann das Kommando nicht sofort wiederholt werden\
}\
}\
\
################################################################################################################\
## 2 Alle Multimedia Geräte abschalten\
##\
2_Media_Aus\
{if (!([$SELF:state] eq "off") ## DOIF enabled\
and ( ([22:00-02:00] and [TV_Wz:state] eq "absent") ## zwischen 22:00 und 2:00 Uhr wenn der fernseher aus geschaltet wurde\
or [02:01] ## aber aufjeden Fall um 2:00 Uhr morgens\
or [$SELF:cmd_event] eq "set_cmd_2" ## Das reagiert auf den Aufruf mit "set <Device> cmd_*"\
or [$SELF:ui_command] eq "Standby Steckdose aus" )) { ## Hier wird das uiTable select ausgewärtet\
\
fhem_set("TV_Wz poweroff");; ## zuerst den Fernseher abschalten, ansonsten geht er morgens direkt an\
if (AttrVal("$SELF","verbose",0) >=3)\
{Log 3, "$SELF : Standby Fernseher abschalten"};; ## hier kommt mal eine Meldung ins Log\
\
set_Exec("Standby_timer",5,'Standby_Steckdose("off")');; ## Die Steckdose etwas verzögert abschalten\
\
set_Reading("ui_command","---");; ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\
## kann das Kommando nicht sofort wiederholt werden\
}\
}\
\
################################################################################################################\
## 3 Definition von Sub Routinen\
subs {\
sub Standby_Steckdose($) { ## Es soll verzögert geschaltet werden\
my ($status) = @_;; ## Hier kommt on/off\
if (AttrVal("$SELF","verbose",0) >=3)\
{Log 3, "$SELF : Standby Steckdose $status"};; ## mal wwieder was für's Log\
fhem_set("shelly06 $status 0");; ## Das schaltet die Steckdose ein/aus\
}\
}
attr Wohnzimmer_Standby DbLogExclude .*
attr Wohnzimmer_Standby alias Wohnzimmer_Standby
attr Wohnzimmer_Standby comment Version 2021.09.13 15:00
attr Wohnzimmer_Standby group PV Eigenverbrauch-Steuerung
attr Wohnzimmer_Standby icon clock
attr Wohnzimmer_Standby room Strom->Photovoltaik
attr Wohnzimmer_Standby sortby 493
attr Wohnzimmer_Standby uiTable {\
package ui_Table;;\
$TC{1..5}="align='center'";; ## Spalten 1 bis 5 werden zentriert\
}\
\
"Kommando<dd>Auswahl </dd>" | widget([$SELF:ui_command],"uzsuDropDown,---,Standby Steckdose ein,Standby Steckdose aus")\
attr Wohnzimmer_Standby verbose 3
setstate Wohnzimmer_Standby 2021-09-15 07:30:00 ui_command ---
Zitat von: Sany am 13 September 2021, 17:07:01
dein sub muss noch in einen subs-Block. In den Beispielen hat Damian den auch immer am Anfang geschrieben, kann sein, daß die Reihenfolge egal ist. Ich fang immer an mit
init {
...
}
subs {
sub abc {
...
}
sub def {
...
}
}
meinBlock1 {
...
}
...
hier nur zur Info: Der subs-Block wird immer als erster ausgeführt, damit alle Perlfunktionen rechtzeitig definiert sind. Die Reihenfolge der Blöcke ist also egal.
Zitat von: Damian am 15 September 2021, 18:15:42
hier nur zur Info: Der subs-Block wird immer als erster ausgeführt, damit alle Perlfunktionen rechtzeitig definiert sind. Die Reihenfolge der Blöcke ist also egal.
Vielen Dank, das ist bereits drin, nur halt als letztes unter dem Kommentar "## 3 Definition von Sub Routinen"
Zitat von: ch.eick am 15 September 2021, 22:03:07
Vielen Dank, das ist bereits drin, nur halt als letztes unter dem Kommentar "## 3 Definition von Sub Routinen"
Zu bedenken ist noch, dass die subs im Package DOIF definiert werden. Das hat zur Folge, dass man sie direkt im Perlmodus nutzen kann, denn der Perlmodus befindet sich gekapselt im DOIF-Package - eigene Perlfunktionen können so nicht FHEM-Perlfunktionen (package main) überschreiben.
Allerdings muss man beachten, dass sich selbst definierte Perlfunktionen in verschiedenen DOIF-Devices überschreiben können, da sich alle DOIF-Devices im DOIF-Package befinden.
Wenn man auf Nummer sicher gehen will, dann kann man im subs-Block vor der Definition der eigenen Perlfunktionen ein eigenes Package definieren z. B.
package mypackage1;
, dann muss man die Funktionen mit package-Angabe aufrufen, hier dann
mypackage1::myfunction....
, statt einem selbst gewählten Namen, hier
mypackage1 kann man auch
$SELF angeben, dann hat man auf jeden Fall in jedem DOIF-Device ein eindeutiges Package, welches nicht mit anderen kollidiert.