Summe aller Einschaltzeiten eines Gerätes: Unterschied zwischen den Versionen
(Die Seite wurde neu angelegt: „Dieses Beispiel ermittelt aus der Datenbank die Einschaltdauer eines Kühlschrankes (über einen Zwischenstecker HM-ES-PMSw1-Pl) innerhalb der letzten 24 Stund…“) |
Krikan (Diskussion | Beiträge) K (kategorisiert) |
||
Zeile 259: | Zeile 259: | ||
Wie üblich können die Auswertungszeitgrenzen durch die Zeit-spezifischen Attribute timestamp_begin, timestamp_end usw. den Anforderungen entsprechend abgeändert werden. | Wie üblich können die Auswertungszeitgrenzen durch die Zeit-spezifischen Attribute timestamp_begin, timestamp_end usw. den Anforderungen entsprechend abgeändert werden. | ||
[[Kategorie:Code Snippets]] |
Version vom 7. Dezember 2017, 22:43 Uhr
Dieses Beispiel ermittelt aus der Datenbank die Einschaltdauer eines Kühlschrankes (über einen Zwischenstecker HM-ES-PMSw1-Pl) innerhalb der letzten 24 Stunden. Wie üblich kann der Auswertungszeitraum über die Time-spezifischen Attribute abgeändert werden.
Es wird angenommen, dass "Aus" = 0 ist und "Ein" ein von 0 abweichender Wert (1 oder eine andere Zahl).
Es sind zwei Komponenten notwendig, ein DbRep-Device und eine Subroutine "switchontime" in der 99_myUtils. Diese Auswertungsroutine kann abweichend davon auch in einer eigenen 99_xxxUtils.pm, z.B. 99_myOntimeUtils.pm, eingebaut werden. Diese Datei ist in das FHEM-Verzeichnis zu kopieren (üblicherweise /opt/fhem/FHEM).
DbRep-Device
Das DbRep-Device wird entsprechend dieser Raw-Definition angelegt:
define Rep.powerOnTime DbRep LogDB attr Rep.powerOnTime aggregation no attr Rep.powerOnTime comment Ermittlung der Anschaltdauer (Switch-on Time) eines Gerätes (z.B. Kühlschrank) \ innerhalb der letzten 24 Stunden.\ Es wird die Auswertungsroutine "switchontime" im Attribut "userExitFn" benötigt \ (in 99_myOntimeUtils.pm enthalten).\ \ Start erfolgt mit: "set <;Name>; fetchrows history" attr Rep.powerOnTime devStateIcon connected:10px-kreis-gelb .*disconnect:10px-kreis-rot .*done:10px-kreis-gruen attr Rep.powerOnTime device eg.az.fridge_Pwr attr Rep.powerOnTime event-on-update-reading state,switch_on_time_sec attr Rep.powerOnTime reading power attr Rep.powerOnTime room DbLog attr Rep.powerOnTime timeDiffToNow 86400 attr Rep.powerOnTime userExitFn switchontime attr Rep.powerOnTime verbose 2
Natürlich ist das angegeben DbLog-Device (LogDB) in der Definition, sowie die Attribute device und reading den eigenen Gegebenheiten anzupassen. Wichtig ist die Angabe:
attr Rep.powerOnTime userExitFn switchontime
was die Aktivierung der userExit-Funktion bzw. den Aufruf der Auswertungsroutine "switchontime" bewirkt.
Die Daten in der Datenbank befinden sich im Device "eg.az.fridge_Pwr" und dem Reading "power". Daraus resultiert dass nach einem
set <Name> fetchrows history
Readings mit folgenden Muster generiert werden.
2017-11-22_16-26-50__eg.az.fridge_Pwr__power 0 2017-11-22 18:33:50 2017-11-22_16-29-54__eg.az.fridge_Pwr__power 0 2017-11-22 18:33:50 2017-11-22_16-32-43__eg.az.fridge_Pwr__power 57.83 2017-11-22 18:33:50 2017-11-22_16-35-18__eg.az.fridge_Pwr__power 51.09 2017-11-22 18:33:50 2017-11-22_16-37-39__eg.az.fridge_Pwr__power 50.13 2017-11-22 18:33:50 2017-11-22_16-39-45__eg.az.fridge_Pwr__power 50.17 2017-11-22 18:33:50 2017-11-22_16-42-40__eg.az.fridge_Pwr__power 49.59 2017-11-22 18:33:50 2017-11-22_16-45-22__eg.az.fridge_Pwr__power 48.57 2017-11-22 18:33:50 2017-11-22_16-47-48__eg.az.fridge_Pwr__power 47.48 2017-11-22 18:33:50 2017-11-22_16-50-01__eg.az.fridge_Pwr__power 46.97 2017-11-22 18:33:50 2017-11-22_16-53-03__eg.az.fridge_Pwr__power 46.02 2017-11-22 18:33:50 2017-11-22_16-53-05__eg.az.fridge_Pwr__power 11.09 2017-11-22 18:33:50 2017-11-22_16-53-13__eg.az.fridge_Pwr__power 0 2017-11-22 18:33:50 2017-11-22_18-14-05__eg.az.fridge_Pwr__power 0 2017-11-22 18:33:50 2017-11-22_18-16-39__eg.az.fridge_Pwr__power 0 2017-11-22 18:33:50 2017-11-22_18-18-58__eg.az.fridge_Pwr__power 0 2017-11-22 18:33:50 2017-11-22_18-21-03__eg.az.fridge_Pwr__power 0 2017-11-22 18:33:50 2017-11-22_18-23-58__eg.az.fridge_Pwr__power 0 2017-11-22 18:33:50 2017-11-22_18-26-08__eg.az.fridge_Pwr__power 56.37 2017-11-22 18:33:50 2017-11-22_18-26-38__eg.az.fridge_Pwr__power 43.22 2017-11-22 18:33:50 2017-11-22_18-29-04__eg.az.fridge_Pwr__power 50.92 2017-11-22 18:33:50 2017-11-22_18-31-16__eg.az.fridge_Pwr__power 50.12 2017-11-22 18:33:50
Auswertungsroutine "switchontime"
Die nachfolgende Auswertungsroutine wird z.B. in der Datei 99_myOntimeUtils.pm gespeichert. Der Code ist mit Kommentaren angereichert um den Ablauf der Auswertung verständlich darzustellen und dadurch eine abgewndelte Nutzung in eigenen Projekten zu erleichtern.
Den Code in die Datei kopieren:
############################################################################
# $Id: myUtilsTemplate.pm 7570 2015-01-14 18:31:44Z rudolfkoenig $
#
package main;
use strict;
use warnings;
use POSIX;
use Time::Local;
sub
myOntimeUtils_Initialize($$)
{
my ($hash) = @_;
}
############################################################################################################
## Ermitteln der Einschaltzeiten eines Gerätes
############################################################################################################
# Im DbRep-Device ist das Attribut "userExitFn = switchontime" zu setzen.
# Auswertung wird im DbRep gestartet mit:
#
# set <DbRep-Device> fetchrows history
#
# Die resultierende Switch-on Zeit wird im aufrufenden DbRep-Device in Readings dargestellt:
# switch_on_time -> on-Zeit als formatierte Angabe hhh:mm:ss
# switch_on_time_sec -> on-Zeit als Sekundenwert
#
# Die Routine ist für alle Readings geeignet die Zahlenwerte als Switch-on/off Zustand beinhalten.
# Switch-off = 0
# Swich-off != 0
#
# Nach der Erstellung jedes einzelnen Readings wird die im Attribut "userExitFn" hinterlegte Funktion
# aufgerufen. Es wird der Devicename des aufrufenden Device, Reading und Wert des Readings übergeben.
# Der Aufrufablauf ist:
# 1. Start: state = running
# 2. Übermittlung jedes generierten Readings
# 3. Stop: state = done (bzw. nicht running)
#
###########################################################################################################
my ($esb,$ese,$esl);
my $t = 0; # Variable für resultierende Sekunden
my $pattern = "eg.az.fridge_Pwr__power"; # verwendbarer Teilstring des Switch-on/Switch-off Werte
# enthaltenden Readings (entsprechend anpassen !)
sub switchontime($$$) {
my ($name,$reading,$value) = @_;
my $hash = $defs{$name};
if($reading eq "state" && $value eq "running") {
# der Select wurde gestartet
Log3 $name, 3, "$name - UserExitFn \"ontime\" has been called.";
$t = 0;
return;
}
if($reading =~ /$pattern/) {
# den Timestamp des letzten Payload-Readings unabhängig vom Status
# (switch-on/switch-off) festhalten
my $lstr = (split("__",$reading))[0];
my ($year, $month, $day, $hour, $min, $sec) = ($lstr =~ /(\d+)-(\d+)-(\d+)_(\d+)-(\d+)-(\d+)/);
# Umwandeln in Epochesekunden
$esl = timelocal($sec, $min, $hour, $day, $month-1, $year-1900);
}
if($reading =~ /$pattern/ && $value != 0 && !$esb) {
# Gerät wurde eingeschaltet
# Beginn Zeitperiode (Unix-Timestamp) ermitteln
my $bstr = (split("__",$reading))[0];
my ($year, $month, $day, $hour, $min, $sec) = ($bstr =~ /(\d+)-(\d+)-(\d+)_(\d+)-(\d+)-(\d+)/);
# Umwandeln in Epochesekunden Beginn
$esb = timelocal($sec, $min, $hour, $day, $month-1, $year-1900);
Log3 $name, 4, "$name - Epoche start: $esb (Reading: $reading)";
}
if($reading =~ /$pattern/ && $value == 0 && $esb) {
# Gerät wurde ausgeschaltet
# Ende Zeitperiode (Unix-Timestamp) ermitteln
my $estr = (split("__",$reading))[0];
my ($year, $month, $day, $hour, $min, $sec) = ($estr =~ /(\d+)-(\d+)-(\d+)_(\d+)-(\d+)-(\d+)/);
# Umwandeln in Epochesekunden Ende
$ese = timelocal($sec, $min, $hour, $day, $month-1, $year-1900);
Log3 $name, 4, "$name - Epoche end: $ese (Reading: $reading)";
# Einschaltzeit in Sekunden summieren (Auswerterichtung DESC - neuester TS -> ältester TS)
$t = $t + ($esb - $ese);
Log3 $name, 4, "$name - switch-on time summary: $t seconds";
undef $esb;
return;
}
if($reading eq "state" && $value ne "running") {
# die Selektion ist beendet, Summensekunden in Format hhh:mm:ss umwamdeln
if ($esb) {
# am Ende der Auswertung ist Status immer noch switch-on
# den Last-Timestamp verwenden
$t = $t + ($esb - $esl);
undef $esb;
}
fhem("setreading $name switch_on_time_sec $t");
my $m = int $t/60;
my $s = $t - ($m*60);
my $h = int $m/60;
$m = $m - ($h*60);
my $timestring = sprintf("%03d:%02d:%02d",$h,$m,$s);
fhem("setreading $name switch_on_time $timestring (hhh:mm:ss)");
Log3 $name, 3, "$name - switch-on time was $timestring (hhh:mm:ss)";
}
return;
}
1;
Nun ist der Suchpattern des Beispiels in der Zeile:
my $pattern = "eg.az.fridge_Pwr__power";
so abzuändern, dass ein auswertbarer Teilstring des Readingsnamens mit den Switch-on/Switch-off Informationen enthalten ist.
Im Fall dass das Device "Ttim" und das Reading "state" heißt, wäre dies z.B.:
my $pattern = "Ttim__state";
Wenn man sich nicht sicher ist, kann durch die Ausführung von:
set <Name> fetchrows history
geprüft werden welche Readings im DbRep-Device erstellt werden und benutzt den Teilstring nach dem führenden Datum/Zeit-String des Readings. Also zum Beispiel:
Reading: 2017-11-22_11-08-02__eg.az.fridge_Pwr__power -> Teilstring für $pattern: eg.az.fridge_Pwr__power
Nun die Utils-Datei laden mit:
reload 99_myOntimeUtils.pm
oder FHEM Restart.
Die Auswertung wird nun gestartet mit:
set Rep.powerOnTime fetchrows history
Es werden zwei zusätzliche Readings im Device Rep.powerOnTime generiert, switch_on_time und switch_on_time_sec.
Das Reading switch_on_time_sec ist die summarische "EIN"-Zeit in Sekunden der letzten 24 Stunden und kann gut zur weiteren Auswertung genutzt werden.
switch_on_time ist eine in hhh:mm:ss formatierte Angabe des Readingswertes von switch_on_time_sec zur leichteren Lesbarkeit.
Natürlich kann man switch_on_time_sec wiederum loggen um z.B. daraus eine grafische Anzeige zu erstellen, die die Entwicklung der täglichen "EIN"-Zeiten über einen längeren Zeitraum darstellen könnte (z.B. Heizzeiten).
Mit kleinen Abwandlungen könnten zum Beispiel auch die täglichen Raumlüftungszeiten (Fenter "open", "closed") ausgewertet und überwacht werden. Wird die vorgegeben "open"-Zeit unterschritten, könnte ein Alarm ausgelöst werden.
Wie üblich können die Auswertungszeitgrenzen durch die Zeit-spezifischen Attribute timestamp_begin, timestamp_end usw. den Anforderungen entsprechend abgeändert werden.