neue Features: ereignisgesteuertes Perl - DOIF-Perl

Begonnen von Damian, 25 Februar 2018, 21:29:16

Vorheriges Thema - Nächstes Thema

Damian

Zitat von: Ellert am 26 August 2018, 19:10:06
Ich habe die Commandref angepasst, in der Version # $Id: 98_DOIF.pm 17155 2018-08-17 11:45:19Z Damian $, commandref_join.pl zeigt keine Fehler.

- Label eingefügt, damit werden bei Auswahl von Attribut, Set oder Get auch für DOIF die Hilfetexte angezeigt, wenn das globale Attribut language auf DE gestellt ist, s. Bild.

- Kurzreferenz aktualisiert.

Ich werde noch ein paar Rechtschreibfehler in meinem Teil korrigieren und dann einchecken.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Ich habe den neuen DOIF-Sourcecode mit commandref_join bei mir eingebunden, kann aber keine Hilfe zum Attribut sehen. language ist auf DE gesetzt. Ich benutze den f18-Style, muss man noch etwas beachten? "Device specific help"-Knopf funktioniert dagegen für die gesamte Doku wie gewohnt.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Ellert

Du benötigst wenigstens diese Revision von fhemweb.js https://forum.fhem.de/index.php/topic,89778.0.html

Und nicht vergessen den Browsercache zu löschen.

Damian

#33
Zitat von: Ellert am 27 August 2018, 09:41:06
Du benötigst wenigstens diese Revision von fhemweb.js https://forum.fhem.de/index.php/topic,89778.0.html

Und nicht vergessen den Browsercache zu löschen.

fhemweb.js hatte ich schon aktualisiert, aber es war wohl noch der alte Stand im Cache. Nach dem Löschen des Caches klappt es nun.

Die Direkthilfe war mir neu. Wurde das irgendwo hier im Forum thematisiert? Es ist sicherlich eine gute Hilfe für DOIF-Nutzer bei der Vielzahl der Attribute selektiert die passenden Infos zu bekommen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Ellert

Eine vorherige Diskussion ist mir nicht bekannt, ich habe es in den FHEM Code changes gesehen, habe mich aber jetzt erst damit befasst.

Eine Diskussion über die Positionierung des Textes gibt es hier: https://forum.fhem.de/index.php/topic,90592.msg830618.html#msg830618

Es werden noch Befürworter gesucht.

Damian

Zitat von: Ellert am 27 August 2018, 11:49:26
Eine vorherige Diskussion ist mir nicht bekannt, ich habe es in den FHEM Code changes gesehen, habe mich aber jetzt erst damit befasst.

Eine Diskussion über die Positionierung des Textes gibt es hier: https://forum.fhem.de/index.php/topic,90592.msg830618.html#msg830618

Es werden noch Befürworter gesucht.

Ja, ich habe es vorhin gelesen. Wäre nicht ggf. ein eigenes Fenster besser? Das Umsortieren der Reihenfolge könnte durchaus für Verwirrung sorgen. Vermutlich muss man für die Entscheidungsfindung selbst eine oder mehrere intuitive Lösungen realisieren, um die Handhabbarkeit ausprobieren zu können.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

#36
Eine typische Anwendung für Aquaristen: Man möchte über einen längeren Zeitraum einen bestimmten Lichtverlauf mit LEDs simulieren. Das kann sowohl die Lichthelligkeit als auch den Farbton betreffen, hier als Beispiel ein Zweizeiler für bestimmte RGB-Werte.

defmod LED_Simulation DOIF init {@{$_a}=qw/121212 242424 363636 474747 595959 6B6B6B 7D7D7D 8F8F8F A1A1A1 B3B3B3 C4C4C4 D6D6D6 E8E8E8 FAFAFA FFFFFF/;;$_counter=0}\
main {if ([11:10-12:21,+00:04]) {fhem"set Aquarium RGB $_a[$_counter++]";; $_counter=($_counter==@{$_a} ? 0:$_counter)}}


Lässt sich natürlich auch für gemütliche Stunden im Schlafzimmer einsetzen - bitte Uhrzeit und Farbe anpassen :)
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Ellert

@Damian

Ich würde gern unterschiedliche Blockingcalls über Perl-DOIF starten und die Ergebnisse in Readings des DOIF darstellen, s. https://wiki.fhem.de/wiki/Blocking_Call

Ich denke die Subs blockingFn,finishFn und abortFn müssen weiterhin in der 99_myUtils.pm definiert sein und nicht im subs-Block.
Sehe ich das richtig?

Für jeden unterschiedlichen Blockingcall müsste im Gerätehash ein Datendsatz abgelegt werden, z.B.
$hash->{helper}{BLOCKING}{0}
$hash->{helper}{BLOCKING}{1}
...
$hash->{helper}{BLOCKING}{n}

Damit bei "shutdown" und "rereadcfg" alle laufendes Blockingcalls beendet werden, müssten sie in der undefFn von DOIF über BlockingKill beendet werden.

Würdest Du sowas einbauen wollen?
Siehst Du eine andere Möglichkeit?


Damian

Im subs-Block definierte Funktionen sind Systemweit verfügbar. Eine echte Kapselung gibt es hier nicht, bestehende Funktionen werden mit dem gleichen Namen überschrieben. Daher sollte es mit  blockingFn,finishFn und abortFn im subs-Block funktionieren, wenn sie eindeutig sind.

Du kannst einen Codevorschlag für undefFn machen, ich kann es bei mir unter Window eh nicht testen.

Andererseits könnte man einen Block mit Trigger auf shutdown und rereadcfg selbst definieren und  BlockingKill  aufrufen. Der Zugriff auf $hash->{helper}{BLOCKING} ist ja gegeben.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

travelling-man

#39
Zitat von: Damian am 29 Juli 2018, 19:33:41
Ich habe nun die Version v0.3 mit Doku fertiggestellt.

Auszüge aus der Doku:

und

Zur Demonstration der neuen Funktionalität wird hier ein größeres Projekt (ähnlich diesem https://forum.fhem.de/index.php/topic,48847.0.html) vorgestellt, welches eine Einknopf Garagentor-/Rollladen-Steuerung realisiert. Dabei werden zwei Relais (rauf/runter), die sich gegenseitig sperren und automatische Endabschaltung des Tores/Rollos vorausgesetzt.

Zur Funktionsweise: Ein geschlossenes Tor wird beim Tastendruck geöffnet, ein geöffnetes wird geschlossen, wenn während der Laufzeit Taste gedrückt wird, bleibt das Tor stehen, ein erneuter Tastendruck bewegt das Tor in umgekehrte Richtung. Dabei werden unterschiedliche Laufzeiten des Tores (rauf/runter) berücksichtigt, ebenso wird die aktuelle Position des Tores aufgrund der Laufzeit berechnet und im Reading abgelegt.

Der Sourcecode ist weitgehend dokumentiert und kann mit Dummys (switch_up, switch_down) ausprobiert werden.


DOIF subs {                                       # im Block subs werden Perlfunktionen definiert, die innerhalb des DOIFs benutzt werden
sub drive { my ($downup)=@_;                      # Funktion zum Herunterfahren oder Hochfahren des Garagentors
  my $seconds; 
  if ($downup eq "up") {
    fhem"set $_up on";                            # Schalter zum Hochfahren einschalten
    $seconds=$_drive_up_time*(1-$_pos/100);       # Laufzeit in Sekunden berechnen
    $_pos=100;                                    # Endposition vorbelegen
  } else {
    fhem"set $_up on";                            # Schalter zum Herunterfahren einschalten
    $seconds=$_drive_down_time*($_pos/100);       # Laufzeit in Sekunden berechnen
    $_pos=0;                                      # Endposition vorbelegen
  }
  set_Reading("state","drive_$downup",1);         # Status des Modus auf drive_down oder drive_up setzen
  set_Exec("Timer_off",$seconds,"off",$downup);   # Setze Timer zum Abschalten des Switches switch_down oder switch_up
}                                             
 
sub off {                                         # Funktion zum Abschalten des hoch-/runter-Schalters
  my ($downup)=@_;
  if ($downup eq "up") {
    fhem"set $_up off";                           # Schalter zum Hochfahren abschalten
  } else {
    fhem"set $_down off";                         # Schalter zum Herunterfahren  abschalten
  }
  set_Reading("state",$downup,1);                 # setze Status des Moduls auf up oder down
  set_Reading("position",int($_pos),1);           # aktuelle Position im Reading festhalten
}

}

init {                                      # Vorbelegung von Instanzvariablen
   $_up="switch_up";                        # Name des Schalters zum Hochfahren
   $_down="switch_down";                    # Name des Schalters zum Herunterfahren
   $_drive_up_time=15;                      # Fahrzeit des Garagentors nach oben
   $_drive_down_time=10;                    # Fahrzeit des Garagentors nach unten
   $_pos=0;                                 # aktuelle Position des Garagentors (0-down, 100-up)
   set_Reading("position",0,0);             # Reading mit der Position auf 0 setzen
}

main {                                                         # Hauptblock reagiert auf Fernbedienung FS und steuert switch up/down abhängig vom Zustand
if ([FS]) {
  if ([?$SELF] eq "up") {                                      # wenn Garagentor oben dann herunterfahren
    drive ("down");                                            # Garagentor herunterfahren
  } elsif ([?$SELF] eq "drive_up") {                           # Garagentor fährt nach oben
    $_pos = (1 - get_Exec("Timer_off")/$_drive_up_time)*100;   # Position bestimmen
    off ("up");                                                # Garagentor stoppen
    del_Exec("Timer_off");                                     # Timer löschen
    set_Reading("state","stop_drive_up",1);                    # Zustand des Moduls setzen
  } elsif ([?$SELF] eq "drive_down") {                         # Garagentor fährt nach unten
    $_pos = (get_Exec("Timer_off")/$_drive_down_time)*100;     # Position bestimmen
    off ("down");                                              # Garagentor stoppen
    del_Exec("Timer_off");                                     # Timer löschen
    set_Reading("state","stop_drive_down",1);                  # Zustand des Moduls setzen
  } elsif ([?$SELF] eq "stop_drive_up") {                      # Garagentor wurde beim Hochfahren gestoppt
    drive ("down");                                            # Herunterfahren
  } elsif ([?$SELF] eq "stop_drive_down") {                    # Garagentor wurde beim Herunterfahren gestoppt
    drive ("up");                                              # Garagentor Hochfahren
  } else {                                                     # "down-Zustand oder ein sonstiger Anfangszustand
    drive ("up");                                              # Garagentor hochfahren
  }
}
}


Edit: aktuelle Version eingecheckt

Hallo Damian,

wäre es möglich das du den Code um 3 Positionsschalter erweitern könntest?
1. Positionsschalter --> Tor zu
2. Positionsschalter --> Tor auf
3. Positionsschalter --> Tor darf sich nicht öffnen da eine Tür im Tor ist nicht geschlossen

Viele Grüße
T-M

Ellert

#40
Zitat von: Damian am 02 September 2018, 11:57:32
Du kannst einen Codevorschlag für undefFn machen, ich kann es bei mir unter Window eh nicht testen.
Blokierende Funktionsaufrufe (blocking calls)

DOIF verwaltet blockierende Funktionsaufrufe, d.h. die in diesem Zusammenhang gestarteten FHEM-Instanzen werden gelöscht,

  beim Herunterfahren (shutdown),
  Wiedereinlesen der Konfiguration (rereadcfg),
  Änderung der Konfiguration (modify) und
  Deaktivieren des Gerätes (disabled).

Die Handhabung von blockierenden Funktionsaufrufen ist im FHEMwiki erklärt, s. Blocking Call.

Der von der Funktion BlockingCall zurückgegebene Datensatz ist unterhalb von $_blockingcalls abzulegen, z.B.

$_blockingcalls{<blocking call name>} = BlockingCall(<blocking function>, <argument>, <finish function>, <timeout>, <abort function>, <abort argument>) unless(defined($_blockingcalls{<blocking call name>}));

Für unterschiedliche blockierende Funktionen ist jeweil ein eigener Name (<blocking call name>) unterhalb von $_blockingcalls anzulegen.

$_blockingcalls ist eine für DOIF reservierte Variable und darf nur in der beschriebenen Weise verwendet werden.

Beispieldefinition zum Testen (für Raw definition)

defmod blockingDOIF DOIF subs {\
  # blocking function\
  sub testBlocking($) {\
    my ($pn) = @_;;\
    for (my $i=0;;$i<20;;$i++) { # ist running 20 s\
      sleep 1;; # sleep is blocking\
    }\
    return "$pn|finished";;\
  }\
  # finish function\
  sub testDone($) {\
    my ($string) = @_;;\
    return unless(defined($string));;\
    my ($pn,$ret) = split("\\|", $string);;\
    my $hash = $defs{$pn};;\
    delete($_blockingcalls{test}) if (defined($_blockingcalls{test}));;\
    set_Reading("test_return", $ret, 1);;\
  }\
  # abort function\
  sub testAbort($){\
    my ($pn) = @_;;\
    my $hash = $defs{$pn};;\
    delete($_blockingcalls{test}) if (defined($_blockingcalls{test}));;\
    set_Reading("test_return", "aborted", 1);;\
  }\
}\
\
blockingcall {\
  #BlockingCall($blockingFn, $arg, $finishFn, $timeout, $abortFn, $abortArg);;\
  my $hash = $defs{$SELF};;\
  my $pn = "$SELF";;\
  if ([+60]) { # calls the blocking function every 60 s with timeout of 30 s\
    if (!defined($_blockingcalls{test})) {\
      $_blockingcalls{test} = BlockingCall("testBlocking", $pn, "testDone", 30, "testAbort", $pn);;\
      set_Reading("test_return", "called, pid:$_blockingcalls{test}{pid}", 1);;\
    } \
  }\
}\
init { # calls the blocking function initially with timeout of 15 s. The blocking call will be aborted before finishing \
  my $hash = $defs{$SELF};;\
  my $pn = "$SELF";;\
    if (!defined($_blockingcalls{test})) {\
      $_blockingcalls{test} = BlockingCall("testBlocking", $pn, "testDone", 15, "testAbort", $pn);;\
      set_Reading("test_return", "called first, pid:$_blockingcalls{test}{pid}", 1);;\
    }\
}


Der Patch basiert auf # $Id: 98_DOIF.pm 17155 2018-08-17 11:45:19Z Damian $

Edit: Anlagen entfernt

Damian

OK.

Gibt es eigentlich eine Killer-Anwendung für blocking calls?

Die Definition:

my $hash = $defs{$pn};

sollte in den Blöcken wie auch den Funktionen überflüssig sein, da $hash global definiert ist.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

#42
Zitat von: travelling-man am 02 September 2018, 23:30:36
Hallo Damian,

wäre es möglich das du den Code um 3 Positionsschalter erweitern könntest?
1. Positionsschalter --> Tor zu
2. Positionsschalter --> Tor auf
3. Positionsschalter --> Tor darf sich nicht öffnen da eine Tür im Tor ist nicht geschlossen

Viele Grüße
T-M

Das etwas umfangreichere Beispiel war als Anregung zum Weitermachen gedacht. Die Abfrage eines Sensors über den Zustand des Tores/Rollos, wäre tatsächlich die nächste Aufgabe zum Ausbau der Definition. Es würde mich freuen, wenn jemand den Anfang machen würde, denn nur so lernt man am besten die Funktionsweise eines Moduls kennen. Ich stehe natürlich bereit, Lösungsvorschläge zu korrigieren bzw. zu verbessern.

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

Ellert

Zitat von: Damian am 03 September 2018, 09:46:44
Gibt es eigentlich eine Killer-Anwendung für blocking calls?
Ich verwende BlockingCall für meine Benzinpreisabfrage (Dauer 4s) und eine Wetterdatenabfrage (Dauer 10s).
Ich verwende nicht HTTPMOD oder HTTPUtils, weil ich Mechanize verwende.
Die Daten schreibe ich bisher in einen Dummy und das Löschen der laufenden FHEM-Instanzen beim Neustart und Neueinlesen der Konfiguration hatte ich bisher nicht realisiert.
Diese Geschichten wollte ich in ein DOIF packen, das war der Anlass DOIF im Zusammenhang mit Blockingcall zu betrachten.

Damian

Zitat von: Ellert am 03 September 2018, 10:38:01
Ich verwende BlockingCall für meine Benzinpreisabfrage (Dauer 4s) und eine Wetterdatenabfrage (Dauer 10s).
Ich verwende nicht HTTPMOD oder HTTPUtils, weil ich Mechanize verwende.
Die Daten schreibe ich bisher in einen Dummy und das Löschen der laufenden FHEM-Instanzen beim Neustart und Neueinlesen der Konfiguration hatte ich bisher nicht realisiert.
Diese Geschichten wollte ich in ein DOIF packen, das war der Anlass DOIF im Zusammenhang mit Blockingcall zu betrachten.

Dann wäre das ein guter Aufhänger für ein passendes DOIF-Beispiel vermutlich im Wiki, weil für Commandref zu umfangreich. Wahrscheinlich brauchen wir eine eigene Wiki-Unterseite für DOIF-Perl mit entsprechenden Beispielen. Ich bin noch am sammeln, finde aber jeden Tag neue Anwendungsfälle für sinnvolle Nutzung des Perl-Modus.

Wie gesagt, testen kann ich bei mir schlecht (ein fork funktioniert nicht gut unter Windows ;) ), das müsstest du dann machen. Die Änderungen im Sourcecode halten sich in Grenzen.


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