Hauptmenü

DOIF und Perl Mode

Begonnen von PSI69, 23 September 2018, 17:05:38

Vorheriges Thema - Nächstes Thema

PSI69

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
FHEM auf RPi 5 unter Bookworm mit inzwischen einem ganzen Zoo von Geräten...

amenomade

#1
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?
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

Damian

$_time ist eine echte Perlvariable. In der DOIF-Syntax [:] können keine Perlvariablen angegeben werden.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

PSI69

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
FHEM auf RPi 5 unter Bookworm mit inzwischen einem ganzen Zoo von Geräten...

amenomade

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.
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

PSI69

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
FHEM auf RPi 5 unter Bookworm mit inzwischen einem ganzen Zoo von Geräten...

PSI69

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
FHEM auf RPi 5 unter Bookworm mit inzwischen einem ganzen Zoo von Geräten...

Damian

#7
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.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

PSI69

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
FHEM auf RPi 5 unter Bookworm mit inzwischen einem ganzen Zoo von Geräten...

Damian

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

PSI69

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 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

FHEM auf RPi 5 unter Bookworm mit inzwischen einem ganzen Zoo von Geräten...

PSI69

@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
FHEM auf RPi 5 unter Bookworm mit inzwischen einem ganzen Zoo von Geräten...

PSI69

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
FHEM auf RPi 5 unter Bookworm mit inzwischen einem ganzen Zoo von Geräten...

Damian

#13
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.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

PSI69

@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
FHEM auf RPi 5 unter Bookworm mit inzwischen einem ganzen Zoo von Geräten...