Ich beginne mich gerade mit dem Regelwerk für eine Bewässerungssteuerung zu beschäftigen und dachte mir: OK, warum versuchst Du nicht einmal DOIF im Perl Mode...
Folgendes DOIF triggert leider nicht auf '$_time', wenn ich das so schreibe:
Internals:
DEF init {
$_time=AttrVal("$SELF","wateringtime",0);
$_duration=AttrVal("$SELF","wateringduration",0);
}
subs {
sub ventil_on {
fhem"set Schalter.Ext.Ventile_Sw_01 on";
fhem"set TeleBot message Schalter.Ext.Ventile.Sw.01 on";
set_Reading("state","on",1);
}
sub ventil_off {
fhem"set Schalter.Ext.Ventile_Sw_01 off";
fhem"set TeleBot message Schalter.Ext.Ventile.Sw.01 off";
set_Reading("state","off",1);
}
}
##{if ([16:12]) {ventil_on()}} ## Um 06:00 Uhr wird die Funktion ventil_on aufgerufen
{if ([$_time]) {ventil_on()}}
MODEL Perl
NAME di_Schalter.Ext.Ventile.Sw.01
NR 1094
NTFY_ORDER 50-di_Schalter.Ext.Ventile.Sw.01
STATE initialize
TYPE DOIF
READINGS:
2018-09-23 16:48:29 block_init executed
2018-09-23 16:50:31 mode enabled
2018-09-23 16:50:31 state initialize
2018-09-23 16:48:29 timer_01_c01 error: Wrong timespec : either HH:MM:SS or {perlcode}
Regex:
condition:
0
$hash->{var}{time}=AttrVal("di_Schalter.Ext.Ventile.Sw.01","wateringtime",0);
$hash->{var}{duration}=AttrVal("di_Schalter.Ext.Ventile.Sw.01","wateringduration",0);
1 if ([$hash->{var}{time}]) {ventil_on()}
2
devices:
helper:
globalinit 1
last_timer 1
sleeptimer -1
internals:
itimer:
localtime:
perlblock:
0 init
1
2
init 0
readings:
time:
timeCond:
uiState:
uiTable:
var:
duration 0
time 0
Attributes:
alias Automatikschalter Gartenbewässerung Sw 01
group Automatikschalter
icon helper_doif
room Aussen->Bewässerung
userattr wateringtime wateringduration
wateringduration 10
wateringtime 16:51
Die auskommentierte Variante mit fester Zeitangabe läuft, gefällt mir aber nicht...
Was will ich überhaupt tun damit? Ich wollte Bewässerungsdauer (onfortimer) und -Zeitpunkt für jedes Magnetventil variabel (also einfach über GUI zu ändern) gestalten, ohne jedes Mal für so etwas in den Code zu müssen. Einen Dummy für so etwas wollte ich auch nicht, also stehen die beiden userattr direkt im DOIF. Am liebsten würde ich 'AttrVal("$SELF","wateringtime",0);' direkt in der Zeit-Bedingung an Stelle der Variable benutzen, aber auch das hat nicht funktioniert.
Ich stehe gerade auf dem Schlauch - hat jemend einen Tip für mich, wie ich da wieder runter komme?
Danke Peter
Und if ([[$SELF:wateringtime]]) ?
Ich vermute, [$_time] triggert nicht, da er nicht erkennt, dass es eine Zeitbedingung ist. Ich würde auch [[$_time]] schreiben, ohne Garantie.
Was sagt übrigens die Log mit verbose 5 an die Uhrzeit?
$_time ist eine echte Perlvariable. In der DOIF-Syntax [:] können keine Perlvariablen angegeben werden.
OK danke! Dann versuche ich heute Nachmittag mal ([[$SELF:wateringtime]]) - kann man so auf die Attribute zugreifen? Als Alternative dann die Variable umbenennen und ein Log 5...
Spannend, so wie es aussieht - ich habe gestern noch etwas gebastelt - bekommt man ja alles ohne Dummy in ein DOIF...
Peter
Zitat von: PSI69 am 24 September 2018, 08:22:40
Dann versuche ich heute Nachmittag mal ([[$SELF:wateringtime]]) - kann man so auf die Attribute zugreifen? Als Alternative dann die Variable umbenennen und ein Log 5...
Da bin ich nicht sicher. Nw. mache ich sowas mit userreadings, nicht mit userattr.
Zitat von: amenomade am 24 September 2018, 08:52:50
Da bin ich nicht sicher. Nw. mache ich sowas mit userreadings, nicht mit userattr.
Ich nehme gern die Attribute für solche überwiegend statischen Konfigurationssachen (Zeiträume, etc), da die beim Speichern mit in der Konfig landen. Als Reading müßte ich die Werte ja beim FHEM Start sinnvoll vorbelegen, oder gibt es einen Weg, die mit zu sichern?
Spontan fält mir ein, userattr und userreadings zu definieren, beim Startup die Werte aus den Attribs in die Readings zu kopieren und im DOIF mit den Readings zu arbeiten - von hinten durch die Brust ins Auge...
Wie macht ihr so etwas?
Peter
Die Variante mit den userreadings klappt nun wie gewünscht. Allerdings scheitere ich daran, den Zeitwert, der im Reading als Minutenangabe steht, on-for-timer als Sekunden - also mit 60 multipliziert - zu übergeben. Die Klammern machen mich noch wahnsinnig:
Internals:
DEF ##init {
## $_time=AttrVal("$SELF","wateringtime",0);
## $_duration=AttrVal("$SELF","wateringduration",0);
##}
subs {
sub ventil_on {
fhem"set Schalter.Ext.Ventile_Sw_01 on-for-timer [([$SELF:wateringduration]*60)]";
}
sub ventil_off {
fhem"set Schalter.Ext.Ventile_Sw_01 off";
}
sub ventil_on_info {
fhem"set TeleBot message Schalter.Ext.Ventile.Sw.01 on-for-timer [([$SELF:wateringduration]*60)]";
set_Reading("state","on",1);
}
sub ventil_off_info {
fhem"set TeleBot message Schalter.Ext.Ventile.Sw.01 off";
set_Reading("state","off",1);
}
}
{if ([[$SELF:wateringtime]]) {ventil_on()}} ## Ventil an zur Bewässerungszeit
{if (["^$SELF$:^on$"]){ventil_on()}} ## WebCmd 'on'
{if (["^$SELF$:^off$"]){ventil_off()}} ## WebCmd 'off'
{if ([Schalter.Ext.Ventile_Sw_01] eq "on"){ventil_on_info()}} ## Status vom Ventil übernehmen
{if ([Schalter.Ext.Ventile_Sw_01] eq "off"){ventil_off_info()}} ## Status vom Ventil übernehmen
MODEL Perl
NAME di_Schalter.Ext.Ventile.Sw.01
NR 1094
NTFY_ORDER 50-di_Schalter.Ext.Ventile.Sw.01
STATE initialized
TYPE DOIF
READINGS:
2018-09-24 17:31:16 Device di_Schalter.Ext.Ventile.Sw.01
2018-09-24 17:31:16 block_02 executed
2018-09-24 17:31:13 mode enabled
2018-09-24 17:31:13 state initialized
2018-09-24 17:31:13 timer_01_c01 24.09.2018 18:00:00
2018-09-24 17:25:41 wateringduration 1
2018-09-24 17:25:41 wateringtime 18:00
Regex:
cond:
:
0:
1:
"^di_Schalter.Ext.Ventile.Sw.01$:^on$" ^di_Schalter.Ext.Ventile.Sw.01$:^on$
2:
"^di_Schalter.Ext.Ventile.Sw.01$:^off$" ^di_Schalter.Ext.Ventile.Sw.01$:^off$
3:
4:
5:
attr:
cmdState:
condition:
0 if (DOIF_time_once($hash,0,$wday)) {ventil_on()}
1 if (EventDoIf('^di_Schalter.Ext.Ventile.Sw.01$',$hash,'^on$',0)){ventil_on()}
2 if (EventDoIf('^di_Schalter.Ext.Ventile.Sw.01$',$hash,'^off$',0)){ventil_off()}
3 if (InternalDoIf($hash,'Schalter.Ext.Ventile_Sw_01','STATE') eq "on"){ventil_on_info()}
4 if (InternalDoIf($hash,'Schalter.Ext.Ventile_Sw_01','STATE') eq "off"){ventil_off_info()}
5
days:
devices:
3 Schalter.Ext.Ventile_Sw_01
4 Schalter.Ext.Ventile_Sw_01
all Schalter.Ext.Ventile_Sw_01
helper:
event on
globalinit 1
last_timer 1
sleeptimer -1
triggerDev di_Schalter.Ext.Ventile.Sw.01
triggerEvents:
on
Device: di_Schalter.Ext.Ventile.Sw.01
block_02: executed
triggerEventsState:
on
Device: di_Schalter.Ext.Ventile.Sw.01
block_02: executed
internals:
3 Schalter.Ext.Ventile_Sw_01:STATE
4 Schalter.Ext.Ventile_Sw_01:STATE
all Schalter.Ext.Ventile_Sw_01:STATE
intervalfunc:
itimer:
all di_Schalter.Ext.Ventile.Sw.01
localtime:
0 1537804800
perlblock:
0
1
2
3
4
5
readings:
realtime:
0 18:00:00
time:
0 [di_Schalter.Ext.Ventile.Sw.01:wateringtime]
timeCond:
0 0
timer:
0 0
timers:
0 0
trigger:
triggertime:
1537804800:
localtime 1537804800
hash:
uiState:
uiTable:
Attributes:
alias Automatikschalter Gartenbewässerung Sw 01
group Automatikschalter
icon helper_doif
room Aussen->Bewässerung
userattr wateringtime wateringduration
wateringduration 1
wateringtime 18:00
webCmd on:off
Ein paar Schreibweisen habe ich schon versucht; immer falsch:
2018.09.24 17:26:58 3: set Schalter.Ext.Ventile_Sw_01 on-for-timer [di_Schalter.Ext.Ventile.Sw.01:wateringduration]*60 : please enter the duration in seconds
2018.09.24 17:27:46 3: set Schalter.Ext.Ventile_Sw_01 on-for-timer [di_Schalter.Ext.Ventile.Sw.01:wateringduration*60] : please enter the duration in seconds
2018.09.24 17:28:15 3: set Schalter.Ext.Ventile_Sw_01 on-for-timer [[di_Schalter.Ext.Ventile.Sw.01:wateringduration]*60] : please enter the duration in seconds
2018.09.24 17:31:16 3: set Schalter.Ext.Ventile_Sw_01 on-for-timer [([di_Schalter.Ext.Ventile.Sw.01:wateringduration]*60)] : please enter the duration in seconds
Der einfache Weg wäre, Sekunden in das Reading zu schreiben, denn der erste Eintrag aus dem Log - ohne das '*60' - funktioniert; hm...
Bekomme ich einen Tip?
Peter
Du bist hier auf Perlebene:
Da würde ich vorwiegend in Perl rechnen und nur das Nötigste an FHEM übergeben:
fhem("set Schalter.Ext.Ventile_Sw_01 on-for-timer ".ReadingsVal("$SELF","wateringduration",0)*60);
Es wird bald ein Update für DOIF geben, dann geht das so:
fhem_set("Schalter.Ext.Ventile_Sw_01 on-for-timer ".get_Reading("wateringduration")*60);
Komplett ohne FHEM-Befehle, ist entsprechend effizienter.
Zitat von: Damian am 24 September 2018, 17:57:48
fhem("set Schalter.Ext.Ventile_Sw_01 on-for-timer ".ReadingsVal("$SELF","wateringduration",0)*60);
Danke!
Zitat von: Damian am 24 September 2018, 17:57:48
fhem_set("Schalter.Ext.Ventile_Sw_01 on-for-timer ".get_Reading("wateringduration")*60);
... schöne Aussichten.
Peter
Zitat von: PSI69 am 24 September 2018, 18:23:15
Danke!
... schöne Aussichten.
Peter
ja, siehe https://forum.fhem.de/index.php/topic,84969.msg839273.html#msg839273
Ich habe noch etwas weiter gebastelt...
Internals:
DEF subs {
sub ventil_on {
fhem("set Schalter.Ext.Ventile_Sw_01 on-for-timer ".AttrVal("$SELF","wateringduration",0)*60);
}
sub ventil_off {
fhem"set Schalter.Ext.Ventile_Sw_01 off";
}
sub ventil_on_info {
set_Reading("state","on",1);
my $SendDebugMessages = AttrVal("$SELF","senddebugmessages",0);
if ($SendDebugMessages == 1) {
SendMessage("mt_Watering", "Magnetventil 'Schalter.Ext.Ventile.Sw.01' on-for-timer ".AttrVal("$SELF","wateringduration",0)*60);
}
}
sub ventil_off_info {
set_Reading("state","off",1);
my $SendDebugMessages = AttrVal("$SELF","senddebugmessages",0);
if ($SendDebugMessages == 1) {
SendMessage("mt_Watering", "Magnetventil 'Schalter.Ext.Ventile.Sw.01' off");
}
}
}
## Ventil an zur Bewässerungszeit
{if ([Schalter.Ext.Ventile.Auto:"on"] && [$SELF:wateringtime|So Mo Di Mi Do Fr Sa]) {ventil_on()}}
## WebCmd 'on' / 'off'
{if (["^$SELF$:^on$"]){ventil_on()}}
{if (["^$SELF$:^off$"]){ventil_off()}}
## Status vom Ventil übernehmen
{if ([Schalter.Ext.Ventile_Sw_01] eq "on"){ventil_on_info()}}
{if ([Schalter.Ext.Ventile_Sw_01] eq "off"){ventil_off_info()}}
MODEL Perl
NAME di_Schalter.Ext.Ventile.Sw.01
NR 1094
NTFY_ORDER 50-di_Schalter.Ext.Ventile.Sw.01
STATE initialized
TYPE DOIF
OLDREADINGS:
READINGS:
2018-09-25 20:12:55 Device di_Schalter.Ext.Ventile.Sw.01
2018-09-25 20:12:55 block_01 executed
2018-09-25 20:10:34 mode enabled
2018-09-25 20:10:34 state initialized
2018-09-25 20:12:55 wateringtime 20:13
Regex:
cond:
:
0:
1:
"^di_Schalter.Ext.Ventile.Sw.01$:^on$" ^di_Schalter.Ext.Ventile.Sw.01$:^on$
2:
"^di_Schalter.Ext.Ventile.Sw.01$:^off$" ^di_Schalter.Ext.Ventile.Sw.01$:^off$
3:
4:
5:
attr:
cmdState:
condition:
0 if (EventDoIf('Schalter.Ext.Ventile.Auto',$hash,'on',1) && ReadingValDoIf($hash,'di_Schalter.Ext.Ventile.Sw.01','wateringtime|So Mo Di Mi Do Fr Sa')) {ventil_on()}
1 if (EventDoIf('^di_Schalter.Ext.Ventile.Sw.01$',$hash,'^on$',0)){ventil_on()}
2 if (EventDoIf('^di_Schalter.Ext.Ventile.Sw.01$',$hash,'^off$',0)){ventil_off()}
3 if (InternalDoIf($hash,'Schalter.Ext.Ventile_Sw_01','STATE') eq "on"){ventil_on_info()}
4 if (InternalDoIf($hash,'Schalter.Ext.Ventile_Sw_01','STATE') eq "off"){ventil_off_info()}
5
devices:
0 Schalter.Ext.Ventile.Auto di_Schalter.Ext.Ventile.Sw.01
3 Schalter.Ext.Ventile_Sw_01
4 Schalter.Ext.Ventile_Sw_01
all Schalter.Ext.Ventile.Auto di_Schalter.Ext.Ventile.Sw.01 Schalter.Ext.Ventile_Sw_01
helper:
event wateringtime: 20:13
globalinit 1
last_timer 0
sleeptimer -1
triggerDev di_Schalter.Ext.Ventile.Sw.01
triggerEvents:
wateringtime: 20:13
Device: di_Schalter.Ext.Ventile.Sw.01
block_01: executed
triggerEventsState:
wateringtime: 20:13
Device: di_Schalter.Ext.Ventile.Sw.01
block_01: executed
internals:
3 Schalter.Ext.Ventile_Sw_01:STATE
4 Schalter.Ext.Ventile_Sw_01:STATE
all Schalter.Ext.Ventile_Sw_01:STATE
itimer:
perlblock:
0
1
2
3
4
5
readings:
0 di_Schalter.Ext.Ventile.Sw.01:wateringtime|So Mo Di Mi Do Fr Sa
all di_Schalter.Ext.Ventile.Sw.01:wateringtime|So Mo Di Mi Do Fr Sa
trigger:
all Schalter.Ext.Ventile.Auto
uiState:
uiTable:
Attributes:
alias Automatikschalter Gartenbewässerung Sw 01
group Automatikschalter
icon helper_doif
room Aussen->Bewässerung
senddebugmessages 1
userattr wateringtime wateringduration senddebugmessages
verbose 5
wateringduration 1
wateringtime 18:00
webCmd on:off
... und bin natürlich wieder einmal über ein Problem gestolpert:
## Ventil an zur Bewässerungszeit
{if ([Schalter.Ext.Ventile.Auto:"on"] && [$SELF:wateringtime|So Mo Di Mi Do Fr Sa]) {ventil_on()}}
Sobald dort '|So Mo Di Mi Do Fr Sa' hinzugefügt wird, wird nicht mehr auf 'wateringtime' getriggert. So hier klappt der Ausdruck:
## Ventil an zur Bewässerungszeit
{if ([Schalter.Ext.Ventile.Auto:"on"] && [$SELF:wateringtime]) {ventil_on()}}
Auch mit verbose 5 am DOIF steht rein gar nichts dazu im Log.
Hier https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung (https://fhem.de/commandref_DE.html#DOIF_Zeitsteuerung) steht die Syntax allerdings als eine mögliche drin?!?
Eigentlich will ich das dann noch so schreiben:
## Ventil an zur Bewässerungszeit
{if ([Schalter.Ext.Ventile.Auto:"on"] && [$SELF:wateringtime|$SELF:wateringdays]) {ventil_on()}}
Unterscheidet sich hier der Perl Mode vom 'normalen' DOIF?
Danke Peter
@Damian
Ein weitere Frage:
Ich habe jetzt genau 6 dieser DOIFs - je eines für jedes Magnetventil. Das Problem ist, alle sind identisch; es sind in subs also genau die selben Funktionen definiert. Somit gewinnt derzeit das DOIF, was ich zuletzt geändert habe. Habe ich jetzt eine andere Wahl, als jeweils die 4 Funktionen umzubenennen, sodass die Namen eineindeutig sind?
Danke Peter
Zitat von: PSI69 am 25 September 2018, 20:39:41
Ich habe jetzt genau 6 dieser DOIFs - je eines für jedes Magnetventil. Das Problem ist, alle sind identisch; es sind in subs also genau die selben Funktionen definiert. Somit gewinnt derzeit das DOIF, was ich zuletzt geändert habe. Habe ich jetzt eine andere Wahl, als jeweils die 4 Funktionen umzubenennen, sodass die Namen eineindeutig sind?
Ich habe noch einmal darüber geschlafen - es ist Quatsch, 6* den selben Code irgendwo stehen zu haben. Ich packe das jetzt in die myutils und übergebe als Parameter das $SELF vom DOIF...
Bleiben noch das hier übrig:
Zitat von: PSI69 am 25 September 2018, 20:25:12
## Ventil an zur Bewässerungszeit
{if ([Schalter.Ext.Ventile.Auto:"on"] && [$SELF:wateringtime|So Mo Di Mi Do Fr Sa]) {ventil_on()}}
Sobald dort '|So Mo Di Mi Do Fr Sa' hinzugefügt wird, wird nicht mehr auf 'wateringtime' getriggert. So hier klappt der Ausdruck:
## Ventil an zur Bewässerungszeit
{if ([Schalter.Ext.Ventile.Auto:"on"] && [$SELF:wateringtime]) {ventil_on()}}
Eigentlich will ich das dann noch so schreiben:
## Ventil an zur Bewässerungszeit
{if ([Schalter.Ext.Ventile.Auto:"on"] && [$SELF:wateringtime|$SELF:wateringdays]) {ventil_on()}}
Danke Peter
Dann aber nach dem heutigen Update im DOIF
::ventil_on()
angeben
oder in myutils package DOIF;
vor der Definition der Perlfunktionen angeben.
Der Namensraum im DOIF im Perlmode ist ab heute (zur eigenen Sicherheit :) ) gekapselt.
@Damian
Danke für den Hinweis!
Zitat von: Damian am 26 September 2018, 09:09:39
Der Namensraum im DOIF im Perlmode ist ab heute (zur eigenen Sicherheit :) ) gekapselt.
In allen DOIFs, oder hat jedes seinen eigenen Namespace?
Peter
Zitat von: PSI69 am 26 September 2018, 09:29:04
@Damian
Danke für den Hinweis!
In allen DOIFs, oder hat jedes seinen eigenen Namespace?
Peter
Wie man dem package-Namen entnehmen kann, haben alle DOIFs den gleichen Namensraum, es ist lediglich eine Abgrenzung zum restlichen FHEM-Universum. Funktionen im DOIF definiert sind ja bereits im DOIF-Namensraum, die kann man im DOIF wie bisher mit der einfachen Angabe des Funktionsnamens nutzen.
Zitat von: Damian am 26 September 2018, 10:16:41
Wie man dem package-Namen entnehmen kann, haben alle DOIFs den gleichen Namensraum, es ist lediglich eine Abgrenzung zum restlichen FHEM-Universum. Funktionen im DOIF definiert sind ja bereits im DOIF-Namensraum, die kann man im DOIF wie bisher mit der einfachen Angabe des Funktionsnamens nutzen.
OK, also wie von mir vermutet...
Hast Du noch eine Idee warum das hier
{if ([Schalter.Ext.Ventile.Auto:"on"] && [$SELF:wateringtime|So Mo Di Mi Do Fr Sa]) {ventil_on()}}
nicht triggert (ja, mir ist klar - da stehen für den Test alle Wochentage drin), sobald der Teil ab der '|' hinzugefügt wird? Fehlen mir hier wieder irgendwelche '[]'? So richtig verstanden, wann und wie oft ich die rechteckigen einsetzen muss, habe ich (leider) auch noch nach ca. 2 Jahren noch nicht; hm.
... eben noch einmal in die Commandref gesehen; das müßte doch passen:
{if ([Schalter.Ext.Ventile.Auto:"on"] && [$SELF:wateringtime|[$SELF:wateringdays]]) {ventil_on()}}
Peter
hier steht, wie es funktioniert: https://fhem.de/commandref_DE.html#DOIF_Indirekten_Zeitangaben
[[$SELF:wateringtime]|So Mo Di Mi Do Fr Sa]
bzw.
[[$SELF:wateringtime]|[$SELF:wateringdays]]
Dankeschön! Also doch wieder die vermaledeiten '[]'.
Zitat von: PSI69 am 26 September 2018, 11:33:07
Dankeschön! Also doch wieder die vermaledeiten '[]'.
ja nun, irgendwie muss der Parser wissen, ob du eine direkte Zeit meinst oder eben eine indirekte, das ist nichts besonders und gibt in vielen Programmiersprachen (Stichwort: pointer).