Summe aller Einschaltzeiten eines Gerätes: Unterschied zwischen den Versionen

Aus FHEMWiki
K (kategorisiert)
K (Gliederungsebenen korrigiert)
Zeile 6: Zeile 6:
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).
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 =
== DbRep-Device ==


Das DbRep-Device wird entsprechend dieser '''Raw-Definition''' angelegt:
Das DbRep-Device wird entsprechend dieser '''Raw-Definition''' angelegt:
Zeile 71: Zeile 71:
</pre>
</pre>


= Auswertungsroutine "switchontime" =
== 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.
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.

Version vom 26. Dezember 2017, 21:13 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.

set <Name> fetchrows history
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:

zusätzliche Readings history
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.