Hauptmenü

Bug oder Feature?

Begonnen von eddy242, 03 März 2022, 19:58:11

Vorheriges Thema - Nächstes Thema

eddy242

Hallo Damian,

beim Debuggen bin ich auf ein Phänomen gestossen. Kannst Du bitte mal beide DOIF's anlegen (Achtung: Da sind keine Typos drin, A und B sind jeweils genau so gemeint!!!). Nach dem die Timer abgelaufen sind, habe ich in kollegeB ein Reading mit dem Namen "Durchsage_von_Kollege_A". Das würde bedeuten, dass die Funktion aus dem set_Exec die Namensraumgrenzen der Module überwinden kann? Also die sub setterKollegeA kann von kollegeB aus aufgerufen werden? Das hat mich beim debuggen kirre gemacht aber ich kann es zuverlässig reproduzieren. Wenn das ein Feature ist, muss ich Doif-Modulübergreifend eineindeutig benennen. Bisher habe ich die Timer-Einsprungfunktionen in mehreren Modulen recht banal "setFromTimer" oder ähnliches genannt, das müsste ich dann in Zukunft ändern und bei Copy & Paste gut aufpassen.

defmod kollegeB DOIF subs {\
sub setterKollegeB {\
my ($what) = @_;;\
set_Reading("Durchsage_von_Kollege_B",$what);;\
}\
}\
\
init {\
set_Exec("TimerKollegeA",25,"setterKollegeA('toll_sagt_Kollege_B')");;\
}

und

defmod kollegeA DOIF subs {\
sub setterKollegeA {\
my ($what) = @_;;\
set_Reading("Durchsage_von_Kollege_A",$what);;\
}\
}\
\
init {\
set_Exec("TimerKollegeA",15,"setterKollegeA('toll_sagt_Kollege_A')");;\
}

Damian

Also die Funktionen sind nicht gekapselt, sie befinden sich alle im package DOIF.

Wenn du sie eindeutig machen willst, dann hast du folgende Möglichkeiten:

1) ein eigenes package definieren

2) die Funktion eindeutig machen

beides kannst du mit Hilfe des Preprozessor über $SELF realisieren:


defmod kollegeB DOIF subs {\
package $SELF;
sub setterKollegeB {\
my ($what) = @_;;\
set_Reading("Durchsage_von_Kollege_B",$what);;\
}\
}\
\
init {\
set_Exec("TimerKollegeA",25,"$SELF::setterKollegeA('toll_sagt_Kollege_B')");;\
}

oder mit eindeutigen Funktionsnamen ohne package;

defmod kollegeB DOIF subs {\
sub $SELF_setterKollegeB {\
my ($what) = @_;;\
set_Reading("Durchsage_von_Kollege_B",$what);;\
}\
}\
\
init {\
set_Exec("TimerKollegeA",25,"$SELF_setterKollegeA('toll_sagt_Kollege_B')");;\
}



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

eddy242

Ok vielen Dank, das hilft, dann weiss ich, wie ich das auf Nummer sicher mache.

Nur noch zur Sicherheit:

  • Wie ist es denn mit den $_xxx Variablen, sind die auch im DOIF Package und müssen z.B. via $SELF eindeutig gemacht werden?
  • Dein Hinweis erstreckt sich auf alle Funktionen im subs-Teil. Ich verwende in besagten Modulen z.T. wiederkehrende Funktionsnamen, wie z.B. createInitialReadingsList. Damit hatte ich seltsamerweise noch nie Probleme mit unvorhergesehenen Resultaten, d.h. es wurde immer die Routine aus dem aktuellen Doif-ausgeführt. Wie ist denn genau der Mechanismus, welche Routine wirklich drankommt?

Damian

Zitat von: eddy242 am 04 März 2022, 19:30:44
Ok vielen Dank, das hilft, dann weiss ich, wie ich das auf Nummer sicher mache.

Nur noch zur Sicherheit:

  • Wie ist es denn mit den $_xxx Variablen, sind die auch im DOIF Package und müssen z.B. via $SELF eindeutig gemacht werden?
$_xxx Variablen sind im jeweiligen $hash untergebracht, also sind sie pro DOIF-Device, im Gegensatz zu subs, gekapselt
Zitat
  • Dein Hinweis erstreckt sich auf alle Funktionen im subs-Teil. Ich verwende in besagten Modulen z.T. wiederkehrende Funktionsnamen, wie z.B. createInitialReadingsList. Damit hatte ich seltsamerweise noch nie Probleme mit unvorhergesehenen Resultaten, d.h. es wurde immer die Routine aus dem aktuellen Doif-ausgeführt. Wie ist denn genau der Mechanismus, welche Routine wirklich drankommt?

Es sind Perl-Mechanismen, die letzte Definition gewinnt, welche das ist, kann ich dir nicht sagen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

eddy242

Sorry noch eine pragmatische Frage. Ich habe es nun begonnen umzusetzen, die Variante mit "package $SELF;" trifft meinen Geschmack. Damit sind dann aber AttrVal, get_Reading, ReadingsVal etc aus dem Namensraum verschwunden. Ich kann natürlich jedesmal ein "::" davorstellen, das macht den Code aber unübersichtlicher. Kann ich das mit "use Irgendwas" vereinfachen? 

Damian

#5
Zitat von: eddy242 am 05 März 2022, 09:53:53
Sorry noch eine pragmatische Frage. Ich habe es nun begonnen umzusetzen, die Variante mit "package $SELF;" trifft meinen Geschmack. Damit sind dann aber AttrVal, get_Reading, ReadingsVal etc aus dem Namensraum verschwunden. Ich kann natürlich jedesmal ein "::" davorstellen, das macht den Code aber unübersichtlicher. Kann ich das mit "use Irgendwas" vereinfachen?

package ist aus meiner Sicht auch die elegantere Lösung, da es eine native Perl-Lösung ist.

Es ist Perl geschuldet, dass man sich gleichzeitig nur in einem package befinden kann. Es gibt hier keine Hierarchie. Daher wirst du bei der Nutzung verschiedener packages mit der Angabe des jeweiligen packages leben müssen. :: ist ja schon die Kurzvariante von main::.

Wenn du DOIF-spezifische Funktionen nutzen willst, wie z. B. set_State, so musst du DOIF:: davorstellen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Da fällt mir noch ein.

package-Angabe im Block subs gilt auch nur im Block subs.

D. h. in einem anderen Block gilt weiterhin DOIF-package, wie zuvor, nur die definierte Funktion muss mit $SELF:: angegeben werden, der Rest ändert sich nicht.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

eddy242

Ja das habe ich gerade auch gemerkt. Aus einem Block wollte ich eine Funktion aus dem Subs-Block aufrufen ( ohne $SELF:: ), da wurde dann eine gleichnamige Funktion aus einem anderen Device ausgeführt. Das hatte mir gezeigt, dass ich die Subs-Routinen aus anderen Blöcken (bei mir sind dass dann typischerweise die Blöcke mit den Triggern) mit $SELF:: aufrufen muss.

Ich bin jetzt dann doch zum Schluss gekommen, dass ich meine Routinen eher mit der $SELF_XXX Präprozessorvariante benenne, dann muss ich die DOIF- und FHEM-Funktionen nicht mit :: bzw. DOIF:: bezeichnen plus dass ich aus anderen Blöcken müsste ich auch $SELF:: hinzufügen müsste. Das macht den Code dann doch schlechter lesbar als nur bei der handvoll eigener Subroutinen das $SELF_ zu ergänzen. 

eddy242

Hallo Damian,

ich muss diesen Thread nochmals weiter führen. Laufe seit ein paar Tagen auf eine Anomalie im Log. Ich habe zwar an dem Code der beiden DOIF's in der letzten Zeit kräftig rumgeschraubt, aber nicht an den Stellen, die hier anscheinend das Problem sind. Aber der Reihe nach:

1. Log
2022.11.03 19:19:02.505 1:     main::CallFn                        called by fhem.pl (782)
2022.11.03 19:19:02.505 1:     main::ZWDongle_Read                 called by fhem.pl (3970)
2022.11.03 19:19:02.505 1:     main::ZWDongle_Parse                called by ./FHEM/00_ZWDongle.pm (878)
2022.11.03 19:19:02.505 1:     main::Dispatch                      called by ./FHEM/00_ZWDongle.pm (983)
2022.11.03 19:19:02.505 1:     main::DoTrigger                     called by fhem.pl (4267)
2022.11.03 19:19:02.505 1:     main::CallFn                        called by fhem.pl (3882)
2022.11.03 19:19:02.505 1:     main::DOIF_Notify                   called by fhem.pl (3970)
2022.11.03 19:19:02.505 1:     main::DOIF_Perl_Trigger             called by ./FHEM/98_DOIF.pm (2961)
2022.11.03 19:19:02.505 1:     main::DOIF_block                    called by ./FHEM/98_DOIF.pm (2658)
2022.11.03 19:19:02.505 1:     main::DOIF_CheckCond                called by ./FHEM/98_DOIF.pm (2610)
2022.11.03 19:19:02.505 1:     (eval)                              called by ./FHEM/98_DOIF.pm (2367)
2022.11.03 19:19:02.505 1:     DOIF::DOIF_Licht_Autoabschaltung_runOnLampOn called by (eval 276062543) (6)
2022.11.03 19:19:02.505 1:     DOIF::set_Reading                   called by (eval 121792195) (123)
2022.11.03 19:19:02.505 1:     main::readingsSingleUpdate          called by ./FHEM/98_DOIF.pm (4195)
2022.11.03 19:19:02.505 1:     main::readingsEndUpdate             called by fhem.pl (5168)
2022.11.03 19:19:02.505 1:     main::DoTrigger                     called by fhem.pl (4985)
2022.11.03 19:19:02.505 1:     main::CallFn                        called by fhem.pl (3882)
2022.11.03 19:19:02.505 1:     main::DOIF_Notify                   called by fhem.pl (3970)
2022.11.03 19:19:02.505 1:     main::DOIF_SetState                 called by ./FHEM/98_DOIF.pm (2969)
2022.11.03 19:19:02.505 1:     main::readingsEndUpdate             called by ./FHEM/98_DOIF.pm (2293)
2022.11.03 19:19:02.505 1:     main::DoTrigger                     called by fhem.pl (4985)
2022.11.03 19:19:02.504 1:     main::CallFn                        called by fhem.pl (3882)
2022.11.03 19:19:02.504 1:     main::DOIF_Notify                   called by fhem.pl (3970)
2022.11.03 19:19:02.504 1:     main::DOIF_Perl_Trigger             called by ./FHEM/98_DOIF.pm (2961)
2022.11.03 19:19:02.504 1:     main::DOIF_block                    called by ./FHEM/98_DOIF.pm (2658)
2022.11.03 19:19:02.504 1:     main::DOIF_CheckCond                called by ./FHEM/98_DOIF.pm (2610)
2022.11.03 19:19:02.504 1:     (eval)                              called by ./FHEM/98_DOIF.pm (2367)
2022.11.03 19:19:02.504 1:     main::__ANON__                      called by (eval 276062546) (3)
2022.11.03 19:19:02.504 1: stacktrace:
2022.11.03 19:19:02.504 1: eval: DOIF_Energiebilanz: warning in condition c13
2022.11.03 19:19:02.504 1: PERL WARNING: Argument "Modification of a read-only value attempted at ./FHEM/98..." isn't numeric in numeric gt (>) at (eval 276062546) line 3.


2. Die Condition #13 aus dem DOIF DOIF_Energiebilanz:

###########################################################################################
### Wie viele Endgeräte der Klimaanlage sind an
###########################################################################################
klimaAn {
    my $devicesOn = [remko:status.countOn,0];
    $_consumers{Klima}{Mode}    = ($devicesOn > 0 ? "on" : "off");
    $_consumers{Klima}{Current} = $_consumers{Klima}{Normal}*$devicesOn;
    Log3("$SELF", 3, "$SELF: Remko: Anzahl Devices active changed");
}


3. Die im Log auftauchende Referenz auf das DOIF DOIF_Licht_Autoabschaltung:

###########################################################################################
    ## Ausschalttimer setzen
    ###########################################################################################
    sub $SELF_runOnLampOn {
        my ($myScene,$lampState) = @_;

        ## Normierung für HUE
        $lampState = "off" if ($lampState eq "0");
        $lampState = "on"  if ($lampState eq "1");

        Log3("$SELF", 5, "$SELF: lampTrigger für $myScene mit Geräte-Status $lampState jetzt gestartet");

        $_scenes{$myScene}{LightNow} = $lampState;
       
        set_Reading("$myScene.lampState",$lampState,1);
        set_Reading("$myScene.eternalMode",$_scenes{$myScene}{EternalMode}?"on":"off",1);

        if ($lampState eq "on") {
            Log3("$SELF", 4, "$SELF: Ausschalt-Timer für $myScene jetzt auf $_scenes{$myScene}{TurnOffTime} Sek neu gesetzt");
            set_Exec($myScene,$_scenes{$myScene}{TurnOffTime},"$SELF_safeLampOff('$myScene')");
            set_Reading("$myScene.offTimer","on",1);
            set_Reading("$myScene.timeWhenOff",::hlGetTimeStr(time(),$_scenes{$myScene}{TurnOffTime}),1);
        } else {
            Log3("$SELF", 4, "$SELF: Ausschalt-Timer für $myScene jetzt gelöscht");
            del_Exec($myScene) if (get_Exec($myScene)>0);
            set_Reading("$myScene.timerExtended",0,1);
            set_Reading("$myScene.offTimer","off",1);
            set_Reading("$myScene.timeWhenOff","",1);
            $_scenes{$myScene}{ExtensionCounter} = 0;
        }

        Log3("$SELF", 5, "$SELF: lampTrigger für $myScene mit Geräte-Status $lampState jetzt beendet");
    }


So sehr ich auch suche, ich komme nicht auf die zündende Idee, wo ich mit dem Debugging weiter machen könnte. Da fiel mir diese Diskussion vom Jahresanfang wieder ein. Könnte es irgendwie eine Verschränkung bei den DOIF's geben, z.B. bei irgendeiner Hash-Variablen (von denen ich Gebrauch mache, es aber keine Names-Doppeldeutigkeiten gibt).

Und wie dann noch der ZWDongle ins Spiel kommt, ist mit ein völliges Rätsel. In dem DOIF_Licht_Autoabschaltung werden auch Gerätezustände abgefragt, die via ZWave angebunden sind, aber natürlich ordentlich über FHEM-Devices und nicht "irgendwie" direkt über den Dongle.

Danke für einen Tipp.

Damian

Die Warnung besagt einfach, dass im Vergleich

$devicesOn > 0

$devicesOn nicht numerisch ist.

Dh.

my $devicesOn = [remko:status.countOn,0];

[remko:status.countOn,0] ist nicht numerisch

Was auch immer da zwischendurch stehen mag, mit

[remko:status.countOn:d,0]

wird der Inhalt nach Zahlen gefiltert.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF