Hilfe...mein DOIF erzeugt 100%CPU Auslastung

Begonnen von bismosa, 02 Dezember 2018, 16:18:18

Vorheriges Thema - Nächstes Thema

bismosa

Hallo,

ich bin gerade auf fehlersuche, warum mein FHEM gerade laufend nicht mehr reagieren möchte.
Mein FHEM ist fast Tagesaktuell und läuft auf einem Raspberry Pi 3 B+.

Es scheint so, das mein DOIF damit zu tun hat. Kurze Erklärung, was ich da eigentlich mache:
Sobald ein Fenster geöffnet oder geschlossen ist, werden in ein Dummy durchnummerierte Readings geschrieben. Die benötige ich, um in FTUI eine Tabelle mit den offenen Fenstern darstellen zu können.


(["^Fenster_.*"]
    or ([$SELF:Timer] eq 1 and [+00:01:00])
)({
my $Max=50;
    ##Alle Fenster durchgehen -> Liste Sortieren -> Neuste Öffnung zuerst
    my %hash;
my %hashKaputt;
my %hashBatt;
    my @Devices=devspec2array("NAME=Fenster_.*:FILTER=STATE=Offen"); ##Offen|Kaputt
my @DevicesKaputt=devspec2array("NAME=Fenster_.*:FILTER=STATE=Kaputt");
my @DevicesBatt=devspec2array("NAME=Fenster_.*:FILTER=battery=low");
    foreach my $Device (@Devices){
        $hash{$Device}{"Age"}=ReadingsAge("$Device", "state", 0);
        $hash{$Device}{"Date"}=(split / /, ReadingsTimestamp("$Device", "state", 0))[0];
        $hash{$Device}{"Time"}=(split / /, ReadingsTimestamp("$Device", "state", 0))[1];
        $hash{$Device}{"TTSName"}=AttrVal("$Device", "TTSName", "unbekannt");
##Log 1, (split / /, ReadingsTimestamp("$Device", "state", 0))[1];
        ##my @words = split / /, ReadingsTimestamp("$Device", "state", 0);
        ##Log 1, Dumper(\@words);
    }
foreach my $Device (@DevicesKaputt){
$hashKaputt{$Device}{"Age"}=ReadingsAge("$Device", "state", 0);
        $hashKaputt{$Device}{"Date"}=(split / /, ReadingsTimestamp("$Device", "state", 0))[0];
        $hashKaputt{$Device}{"Time"}=(split / /, ReadingsTimestamp("$Device", "state", 0))[1];
        $hashKaputt{$Device}{"TTSName"}=AttrVal("$Device", "TTSName", "unbekannt");
}
foreach my $Device (@DevicesBatt){
$hashBatt{$Device}{"Age"}=ReadingsAge("$Device", "battery", 0);
        $hashBatt{$Device}{"Date"}=(split / /, ReadingsTimestamp("$Device", "battery", 0))[0];
        $hashBatt{$Device}{"Time"}=(split / /, ReadingsTimestamp("$Device", "battery", 0))[1];
        $hashBatt{$Device}{"TTSName"}=AttrVal("$Device", "TTSName", "unbekannt");
}
    ##Log 1, Dumper(\%hash);
   
    ##Sortieren
    my $i=0;
for (sort { $hash{$a}->{Age} <=>  $hash{$b}->{Age} } keys %hash){
        ##Log 1, "$_ ".$hash{$_}{"Date"}." ".$hash{$_}{"Time"};
       
        ##Readings setzen
        fhem("setreading du_Fenster_liste Name_".sprintf("%02d", $i)." ".$_);
        fhem("setreading du_Fenster_liste Age_".sprintf("%02d", $i)." ".$hash{$_}{"Age"});
        ##fhem("setreading du_Fenster_liste Date_".sprintf("%02d", $i)." ".$hash{$_}{"Date"});
        ##fhem("setreading du_Fenster_liste Time_".sprintf("%02d", $i)." ".$hash{$_}{"Time"});
        fhem("setreading du_Fenster_liste TTSName_".sprintf("%02d", $i)." ".$hash{$_}{"TTSName"});
fhem("setreading du_Fenster_liste State_".sprintf("%02d", $i)." "."0");
       
        my $Age=$hash{$_}{"Age"};
my $Text=Sekunden2TextKurz($Age);
fhem("setreading du_Fenster_liste TextLang_".sprintf("%02d", $i)." $Text");
        $i=$i+1;
    }
fhem("setreading du_Fenster_liste Anzahl $i");
my $iKaputt=0;
for (sort { $hashKaputt{$a}->{Age} <=>  $hashKaputt{$b}->{Age} } keys %hashKaputt){
fhem("setreading du_Fenster_liste Name_".sprintf("%02d", $i)." ".$_);
        fhem("setreading du_Fenster_liste Age_".sprintf("%02d", $i)." ".$hashKaputt{$_}{"Age"});
fhem("setreading du_Fenster_liste TTSName_".sprintf("%02d", $i)." ".$hashKaputt{$_}{"TTSName"});
my $Age=$hashKaputt{$_}{"Age"};
my $Text=Sekunden2TextKurz($Age);
fhem("setreading du_Fenster_liste TextLang_".sprintf("%02d", $i)." $Text");
fhem("setreading du_Fenster_liste State_".sprintf("%02d", $i)." "."1");
        $i=$i+1;
$iKaputt=$iKaputt+1;
}
fhem("setreading du_Fenster_liste AnzahlKaputt $iKaputt");
my $iBatt=0;
for (sort { $hashBatt{$a}->{Age} <=>  $hashBatt{$b}->{Age} } keys %hashBatt){
fhem("setreading du_Fenster_liste Name_".sprintf("%02d", $i)." ".$_);
        fhem("setreading du_Fenster_liste Age_".sprintf("%02d", $i)." ".$hashBatt{$_}{"Age"});
fhem("setreading du_Fenster_liste TTSName_".sprintf("%02d", $i)." ".$hashBatt{$_}{"TTSName"});
my $Age=$hashBatt{$_}{"Age"};
my $Text=Sekunden2TextKurz($Age);
fhem("setreading du_Fenster_liste TextLang_".sprintf("%02d", $i)." $Text");
fhem("setreading du_Fenster_liste State_".sprintf("%02d", $i)." "."2");
        $i=$i+1;
$iBatt=$iBatt+1;
}
fhem("setreading du_Fenster_liste AnzahlBatt $iBatt");
   
    ##Bei Bedarf Timer setzen
if ($i eq 0){
        fhem("setreading $SELF_liste Timer 0");
    }else{
        fhem("setreading $SELF Timer 1");
    }
   
##Die restlichen Einträge entfernen (leerzeichen) ohne löschen
    while ($i < $Max){
        fhem("setreading du_Fenster_liste Name_".sprintf("%02d", $i)." "."&nbsp;");
        fhem("setreading du_Fenster_liste Age_".sprintf("%02d", $i)." "."0");
        fhem("setreading du_Fenster_liste TTSName_".sprintf("%02d", $i)." "."&nbsp;");
        fhem("setreading du_Fenster_liste TextLang_".sprintf("%02d", $i)." "."&nbsp;");
fhem("setreading du_Fenster_liste State_".sprintf("%02d", $i)." "."0");
        $i=$i+1;
    }
   
   

})


myUtils:

sub Sekunden2TextKurz($){
    my $Age=shift;
my $Text;
        if ($Age >= 86400){
            my $Tage=int($Age/86400);
            $Text=$Tage." Tage ";
            $Age=$Age-$Tage*86400;
        }
        my $HasHour=false;
        if ($Age >= 3600){
            my $Stunden=int($Age/3600);
            $Text.=sprintf("%02d:", $Stunden);
            $Age=$Age-$Stunden*3600;
            $HasHour=true;
        }
        if ($Age >= 60){
            my $Minuten=int($Age/60);
            if ($HasHour eq false){
                $Text.=$Minuten;
                $Text.=" Min.";
            } else {
                $Text.=sprintf("%02d", $Minuten);
            }
        } else {
            if ($HasHour eq true){
                $Text.="00"
            } else {
                $Text.="0 Min."
            }
        }
return $Text;
}



Sicherlich werden viele readings erzeugt...derzeit 50x5 (zum testen...aber es bleiben später auch 40x5 Einträge übrig um alle zu erfassen). Erzeugt das eine so große FHEM last?
Mache ich hier etwas grundsätzliches falsch? Oder findet ihr einen anderen Fehler? Ich habe jetzt auch das erste Mal in Perl mit Hash gearbeitet...könnte das damit zusammenhängen?
Derzeit ist es so, dass sobald ein Fenster geöffnet wird FHEM für 30-45 sek. gar nicht mehr reagiert....

Vielleicht gibt es ja auch eine bessere Lösung als so viele Readings zu erzeugen? Aber das habe ich mir eigentlich bei den Kalendern abgeschaut...da ist es ja ähnlich.

Gruß
Bismosa

[edit]
Gerade nochmal perfmon probiert. Das passiert, wenn ein Fenster geöffnet wird:

2018.12.02 16:42:36 2: Perfmon: ready to watch out for delays greater than one second
2018.12.02 16:43:06 1: Perfmon: possible freeze starting at 16:43:02, delay is 4.633
2018.12.02 16:43:16 1: Perfmon: possible freeze starting at 16:43:07, delay is 9.974
2018.12.02 16:43:27 1: Perfmon: possible freeze starting at 16:43:17, delay is 10.241
2018.12.02 16:43:37 1: Perfmon: possible freeze starting at 16:43:28, delay is 9.946
2018.12.02 16:43:50 1: Perfmon: possible freeze starting at 16:43:38, delay is 12.109


Und so sieht es mit apptime aus:

di_Fenster_Liste                         DOIF_Notify                           4812     2700   40819.66    15.12     0.00     0.00 02.12. 16:46:06 HASH(di_Fenster_Liste); HASH(Fenster_EG_Buero_R)

[/edit]
1x nanoCUL 433MHz (SlowRF Intertechno) für Fenstersensoren
1x nanoCUL 868Mhz für MAX (9x HT 1xWT)
1x ZigBee CUL
Weiteres: Squeezebox server, Kindle Display, ESP8266, Löterfahrung, ...

amenomade

Was hat noch dein DOIF für andere Attribute? Ein vollständiges "list" vom DOIF wäre nicht schlecht.

Sonst würde ich nach und nach mehrere Sachen probieren:
- in der Bedingung das mit $SELF:Timer und +1  löschen
- in den "Fenster_.* Trigger ein bisschen spezifischer sein: nur die Readings, die dich interessieren
- das "sort" in den Hashes erstmal weglassen

PS: readingsGroup kann solche Tabellen aufbauen
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

bismosa

Hallo,

danke für die Tipps!
ReadingsGroup habe ich dafür schon länger im Einsatz. Leider klappt es mit der ReadingsGroup und der FTUI mit dem aktualisieren nicht so gut (ich kenne die angepasste Version...möchte aber nicht bei jedem Update darüber nachdenken müssen)

Daher möchte ich nun eine Tabelle im FTUI aufbauen, die "Ähnlichkeiten" hat.

Ich habe nur ein Attribut: "do always". Ich möchte ja auch jedes Mal triggern.

Es macht leider keinen Unterschied, wenn ich " $SELF:Timer und +1 " entferne. Nur das mein FHEM nicht jede Minute bei einem offenen Fenster hängt.
Leider benötige ich alle aufgeführten readings....um das dann sowohl in der Tabelle als auch an den Icons anzuzeigen (unterschiedliche Symbole + unterschiedliche Farben).
Wenn ich es richtig sehe, dann ist das einfach die Fülle an Events die ausgelöst werden.

Ich bin gerade dabei das ganz anders zu lösen...ich erzeuge meinen HTML-Code einfach im DOIF. Dann brauche ich nur ein Reading setzen:

(["^Fenster_.*"]
    or ([$SELF:Timer] eq 1 and [+00:01:00])
)({
my $Max=50;
    my %hash;
my %hashKaputt;
my %hashBatt;
    my @Devices=devspec2array("NAME=Fenster_.*:FILTER=STATE=Offen"); ##Offen|Kaputt
my @DevicesKaputt=devspec2array("NAME=Fenster_.*:FILTER=STATE=Kaputt");
my @DevicesBatt=devspec2array("NAME=Fenster_.*:FILTER=battery=low");
    foreach my $Device (@Devices){
        $hash{$Device}{"Age"}=ReadingsAge("$Device", "state", 0);
        $hash{$Device}{"Date"}=(split / /, ReadingsTimestamp("$Device", "state", 0))[0];
        $hash{$Device}{"Time"}=(split / /, ReadingsTimestamp("$Device", "state", 0))[1];
        $hash{$Device}{"TTSName"}=AttrVal("$Device", "TTSName", "unbekannt");
##Log 1, (split / /, ReadingsTimestamp("$Device", "state", 0))[1];
        ##my @words = split / /, ReadingsTimestamp("$Device", "state", 0);
        ##Log 1, Dumper(\@words);
    }
foreach my $Device (@DevicesKaputt){
$hashKaputt{$Device}{"Age"}=ReadingsAge("$Device", "state", 0);
        $hashKaputt{$Device}{"Date"}=(split / /, ReadingsTimestamp("$Device", "state", 0))[0];
        $hashKaputt{$Device}{"Time"}=(split / /, ReadingsTimestamp("$Device", "state", 0))[1];
        $hashKaputt{$Device}{"TTSName"}=AttrVal("$Device", "TTSName", "unbekannt");
}
foreach my $Device (@DevicesBatt){
$hashBatt{$Device}{"Age"}=ReadingsAge("$Device", "battery", 0);
        $hashBatt{$Device}{"Date"}=(split / /, ReadingsTimestamp("$Device", "battery", 0))[0];
        $hashBatt{$Device}{"Time"}=(split / /, ReadingsTimestamp("$Device", "battery", 0))[1];
        $hashBatt{$Device}{"TTSName"}=AttrVal("$Device", "TTSName", "unbekannt");
}
    ##Log 1, Dumper(\%hash);
   
    ##Sortieren
my $html='<div align="left"><table><tbody>';
    my $i=0;

for (sort { $hash{$a}->{Age} <=>  $hash{$b}->{Age} } keys %hash){
my $Age=$hash{$_}{"Age"};
my $Text=Sekunden2TextKurz($Age);

##Kein Symbol:
$html.="<tr><td></td>";

##Farbe beachten!
##0 900 3600
my $color="";
if ($Age gt 3600){
$color="#FF0000";
} elsif ($Age gt 900){
$color="yellow";
} else {
$color="green";
}
$html.='<td><div style="color:'.$color.'">'.$hash{$_}{"TTSName"}.'</div></td>';
##Abgelaufene Zeit:
$html.='<td><div style="color:'.$color.'">'.$Text.'</div></td>';
$html.="</tr>";
$i=$i+1;
}
fhem("sleep 1; setreading $SELF Anzahl $i");

my $iKaputt=0;
for (sort { $hashKaputt{$a}->{Age} <=>  $hashKaputt{$b}->{Age} } keys %hashKaputt){
my $Age=$hashKaputt{$_}{"Age"};
my $Text=Sekunden2TextKurz($Age);
##Symbol Kaputt:

$html.="<tr><td> <div class=\"tiny compressed\" data-type=\"symbol\" data-icon=\"oa-message_attention\" data-on-color=\"#FF0000\" data-off-color=\"#FF0000\"></div></td>";
my $color="";
if ($Age gt 3600){
$color="#FF0000";
} elsif ($Age gt 900){
$color="yellow";
} else {
$color="green";
}
$html.='<td><div style="color:'.$color.'">'.$hashKaputt{$_}{"TTSName"}.'</div></td>';
##Abgelaufene Zeit:
$html.='<td><div style="color:'.$color.'">'.$Text.'</div></td>';
$html.="</tr>";
$i=$i+1;
$iKaputt=$iKaputt+1;
}
fhem("sleep 1; setreading $SELF AnzahlKaputt $iKaputt");

my $iBatt=0;
for (sort { $hashBatt{$a}->{Age} <=>  $hashBatt{$b}->{Age} } keys %hashBatt){
my $Age=$hashBatt{$_}{"Age"};
my $Text=Sekunden2TextKurz($Age);
##Symbol Kaputt:

$html.="<tr><td> <div class=\"tiny compressed\" data-type=\"symbol\" data-icon=\"oa-measure_battery_0  fa-rotate-90\" data-on-color=\"#FF0000\" data-off-color=\"#FF0000\"></div></td>";
my $color="";
if ($Age gt 3600){
$color="#FF0000";
} elsif ($Age gt 900){
$color="yellow";
} else {
$color="green";
}
$html.='<td><div style="color:'.$color.'">'.$hashBatt{$_}{"TTSName"}.'</div></td>';
##Abgelaufene Zeit:
$html.='<td><div style="color:'.$color.'">'.$Text.'</div></td>';
$html.="</tr>";
$i=$i+1;
$iBatt=$iBatt+1;
}
fhem("sleep 1; setreading $SELF AnzahlBatt $iBatt");

$html.="</tbody></table></div>";
fhem("setreading $SELF HTML $html");
   
    ##Bei Bedarf Timer setzen
if ($i eq 0){
        fhem("setreading $SELF Timer 0");
    }else{
        fhem("setreading $SELF Timer 1");
    }
})


Nun wird nur noch ein Reading erzeugt...und im FTUI brauche ich nur ein Label. Farben und Symbole werden direkt hier generiert. Das läuft flüssig durch. Zumindest merke ich keine außergewöhnliche CPU-Last...und im FTUI wird die Anzeige auch sofort aktualisiert.

Bestimmt nicht im Sinne des Erfinders...aber es klappt wenigstens  :)

Gruß
Bismosa
1x nanoCUL 433MHz (SlowRF Intertechno) für Fenstersensoren
1x nanoCUL 868Mhz für MAX (9x HT 1xWT)
1x ZigBee CUL
Weiteres: Squeezebox server, Kindle Display, ESP8266, Löterfahrung, ...

Damian

Wenn du schon so viel in Perl programmierst, dann kannst du auch gleich den DOIF-Perl-Modus verwenden. Dort gibt es u. a. die Funktion set_Reading, welche ohne Events arbeitet, das ist schon mal fast zwei Zehnerpotenzen performanter.


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

bismosa

Hallo,

ich dachte ich benötige die Events, damit in der Tablet-UI die neuen Werte auch direkt angezeigt werden?
Sicherlich benötige ich nicht immer alle. Wenn ich z.B. nur auf der Hauptseite bin, sind es max. 5 Zeilen. Aber das weiß FHEM ja nicht.
Mit dem einen Event und der im DOIF erzeugten HTML-Tabelle klappt es scheinbar ganz gut...ich habe es jetzt noch etwas optimiert, so dass ich jetzt 2 Readings bekomme. 1x mit max. 5 Zeilen und 1x vollständig. Im FTUI rufe ich dann in einem Label entweder das eine oder das andere auf...

Ich hatte einfach nicht gedacht das 250 Events auf einmal FHEM so blockieren können. Da muss ich direkt mal einige anderen Devices überprüfen...einige erzeugen echt viele Events.

Gruß
Bismosa
1x nanoCUL 433MHz (SlowRF Intertechno) für Fenstersensoren
1x nanoCUL 868Mhz für MAX (9x HT 1xWT)
1x ZigBee CUL
Weiteres: Squeezebox server, Kindle Display, ESP8266, Löterfahrung, ...

Ellert