Hallo!
Ich hab in den letzten Tagen versucht mein Script zur Stromverbrauchs Berechnung über die Laufzeit in ein Modul umzuwandeln. Hab mich durch diverse Wiki- und Foren Einträge geschlagen aber wenn ich ehrlich bin, bin ich nicht schlauer als vorher.
Das Ding macht bisher folgendes: Wenn ich einen Aktor zB. Steckdose, UP-Licht-Schalter, etc. einschalte wird die Start-Zeit ins Reading des Aktors geschrieben. Beim Ausschalten wird dann der Verbrauch berechnet und ins Reading geschrieben. Das funktioniert mittlerweile.
Der Aufruf des Scripts erfolgt derzeit über ein notify. define n_DeckenfluterVerbrauchR notify wzDeckenfluter { stromverbrauch($NAME, <WATT>);; }
Mein Ziel ist es das man das Modul definiert und es per on/off des Aktors automatisch gestartet und beendet wird. In einem Abstand von x Sekunden soll das Modul wenn der Aktor ein ist starten, die Readings neu berechnen und eintragen.
Dieser Abstands soll sowie die Leistung in Watt per Attribut definierbar sein.
Wenn ich das geschafft hab, kommt noch der Verbrauch von Heute, Monat, etc.
Nun meine Frage: Gibt es irgendwo eine Anleitung wie man ein Modul erstellt die ich übersehen hab? Oder kann mir das vielleicht jemand erklären?
Viele Grüße,
fhainz
Und sry falls ich das falsche Forum erwischt hab. Wusste nicht genau wohin damit ;)
Ich hab jetzt einfach versucht aus vorhandenen Modulen mir etwas zusammen zu kopieren.
Wie zu erwarten funktioniert das ganze nicht ;)
Ich schaff es nicht mal das Modul zu definieren, bekomm immer Unknown module currentCalculator . Kann mir jemand sagen was ich alles falsch mache? Hab ich es wenigstens ansatzweise richtig gemacht oder bin ich komplett am falschen weg?
Hier mal das Modul:
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday sleep);
sub currentCalculator_Get($@);
sub currentCalculator_Define($$);
sub currentCalculator_GetStatus($;$);
sub currentCalculator_Undefine($$);
sub
currentCalculator_Initialize($)
{
my ($hash) = @_;
$hash->{GetFn} = "currentCalculator_Get";
$hash->{SetFn} = "currentCalculator_Set";
$hash->{DefFn} = "currentCalculator_Define";
$hash->{UndefFn} = "currentCalculator_Undefine";
$hash->{ParseFn} = "currentCalculator_ParseFn";
}
#####################################
sub
currentCalculator_Define($$)
{
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
return "Usage: define <name> currentCalculator [aktor] [watt] [invterval]" if(@a < 4 || @a > 5);
my $name = $a[0];
my $device = $a[2];
my $watt = $a[3];
my $interval = 60;
$interval = $a[4] if($interval < 60);
$hash->{NAME} = $name;
$hash->{DEVICE} = $device;
$hash->{STATE} = "Active";
$hash->{INTERVAL} = $interval;
$hash->{WATT} = $watt;
return undef;
}
sub
currentCalculator_Set()
{}
sub currentCalculator_Undefine($$)
{}
sub
currentCalculator_ParseFn($)
{
my ($hash) = @_;
my $name = $hash->{NAME};
my $device = $hash->{DEVICE};
#----- Untoggle Fix-----#
if ( Value($hash->{DEVICE}) eq "toggle" ) {
if ( OldValue($hash->{DEVICE}) eq "off" ) {
fhem("set $device on");
}
else {
fhem("set $device off");
}
}
my $on = "";
$hash->{ON} = $on;
if ( Value($device) eq "on" ) {
$hash->{ON} = int( time() );
speedtest_setReading( $hash->{DEVICE}, "on", $hash->{ON} );
speedtest_setReading( $hash->{DEVICE}, "power", $hash->{WATT} );
}
elsif ( Value($device) eq "off" ) {
currentCalculator_berechnen( $hash->{DEVICE}, $hash->{WATT} );
}
else {
Log3 $hash->{NAME}, 3, "Untoggle Problem";
}
}
#----- Stromverbrauch berechnen -----#
sub
currentCalculator_Berechnen($)
{
my ($hash) = @_;
$hash->{ON} = ReadingsVal( $hash->{DEVICE}, "on", "0" );
$hash->{OFF} = int( time() );
$hash->{ONLAST} = $hash->{OFF} - $hash->{ON};
$hash->{ONTOTAL} = ReadingsVal( $hash->{DEVICE}, "onTotal", "0" );
$hash->{CONSUMPTIONTOTAL} = ReadingsVal( $hash->{DEVICE}, "consumptionTotal", "" );
$hash->{ONTOTAL} = int( $hash->{ONTOTAL} + $hash->{ONLAST} );
$hash->{CONSUMPTIONLAST} = $hash->{ONLAST} * $hash->{WATT} / 1000 / 3600;
$hash->{CONSUMPTIONTOTAL} = $hash->{CONSUMPTIONTOTAL} + $hash->{CONSUMPTIONLAST};
#$consumptionTotal = sprintf "%.2f", $consumptionTotal;
if ( $hash->{ON} > 0 ) {
setReading( $hash->{DEVICE}, "on", 0 );
setReading( $hash->{DEVICE}, "off", $hash->{OFF} );
setReading( $hash->{DEVICE}, "onLast", $hash->{ONLAST} );
setReading( $hash->{DEVICE}, "onTotal", $hash->{ONTOTAL} );
setReading( $hash->{DEVICE}, "power", "0" );
setReading( $hash->{DEVICE}, "consumptionTotal", $hash->{CONSUMPTIONTOTAL} );
}
else {
Log3 $hash->{DEVICE}, 3, "Keine Startzeit ermittelt";
}
}
#----- setReading -----#
sub setReading($$$) {
my ($hash, $readingsName, $readingsWert) = @_;
readingsBeginUpdate( $hash );
readingsBulkUpdate( $hash, $readingsName, $readingsWert );
readingsBulkUpdate( $hash, $readingsName, $readingsWert );
readingsEndUpdate( $hash, 1 );
}
Ich hoffe mir kann jemand weiterhelfen.
Grüße
ganz ans ende muss ein 1;
sonst läd fhem das modul nicht.
für die notifys ist notifyFn zuständig. nicht parseFn.
es taucht noch ein spendetest_... auf. das ist ziemlich sicher nicht beabsichtig.
die mehrfachen readingsBeginUpdate/readingsEndUpdate sind nicht optimal. die würde ich auf einen rutsch schreiben.
gruss
andre
Ich hab die Punkte geändert. Nun schmiert FHEM direkt nach dem speichern der fhem.cfg ab.
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday sleep);
sub currentCalculator_Get($@);
sub currentCalculator_Define($$);
sub currentCalculator_GetStatus($;$);
sub currentCalculator_Undefine($$);
sub currentCalculator_Initialize($) {
my ($hash) = @_;
$hash->{GetFn} = "currentCalculator_Get";
$hash->{SetFn} = "currentCalculator_Set";
$hash->{DefFn} = "currentCalculator_Define";
$hash->{UndefFn} = "currentCalculator_Undefine";
$hash->{NotifyFn} = "currentCalculator_NotifyFn";
}
#####################################
sub currentCalculator_Define($$) {
my ( $hash, $def ) = @_;
my @a = split( "[ \t][ \t]*", $def );
return "Usage: define <name> currentCalculator [aktor] [watt] [invterval]"
if ( @a < 4 || @a > 5 );
my $name = $a[0];
my $device = $a[2];
my $watt = $a[3];
my $interval = 60;
$interval = $a[4] if ( $interval < 60 );
$hash->{NAME} = $name;
$hash->{DEVICE} = $device;
$hash->{STATE} = "Active";
$hash->{INTERVAL} = $interval;
$hash->{WATT} = $watt;
return undef;
}
sub currentCalculator_Set() {
}
sub currentCalculator_Undefine($$) { }
sub currentCalculator_NotifyFn($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $device = $hash->{DEVICE};
#----- Untoggle Fix-----#
if ( Value( $hash->{DEVICE} ) eq "toggle" ) {
if ( OldValue( $hash->{DEVICE} ) eq "off" ) {
fhem("set $device on");
}
else {
fhem("set $device off");
}
}
my $on = "";
$hash->{ON} = $on;
if ( Value($device) eq "on" ) {
$hash->{ON} = int( time() );
setReading( $hash->{DEVICE}, "on", $hash->{ON} );
setReading( $hash->{DEVICE}, "power", $hash->{WATT} );
}
elsif ( Value($device) eq "off" ) {
currentCalculator_berechnen( $hash->{DEVICE}, $hash->{WATT} );
}
else {
Log3 $hash->{NAME}, 3, "Untoggle Problem";
}
}
#----- Stromverbrauch berechnen -----#
sub currentCalculator_Berechnen($) {
my ($hash) = @_;
$hash->{ON} = ReadingsVal( $hash->{DEVICE}, "on", "0" );
$hash->{OFF} = int( time() );
$hash->{ONLAST} = $hash->{OFF} - $hash->{ON};
$hash->{ONTOTAL} = ReadingsVal( $hash->{DEVICE}, "onTotal", "0" );
$hash->{CONSUMPTIONTOTAL} = ReadingsVal( $hash->{DEVICE}, "consumptionTotal", "" );
$hash->{ONTOTAL} = int( $hash->{ONTOTAL} + $hash->{ONLAST} );
$hash->{CONSUMPTIONLAST} = $hash->{ONLAST} * $hash->{WATT} / 1000 / 3600;
$hash->{CONSUMPTIONTOTAL} = $hash->{CONSUMPTIONTOTAL} + $hash->{CONSUMPTIONLAST};
#$consumptionTotal = sprintf "%.2f", $consumptionTotal;
if ( $hash->{ON} > 0 ) {
setReading( $hash->{DEVICE}, "on", 0 );
setReading( $hash->{DEVICE}, "off", $hash->{OFF} );
setReading( $hash->{DEVICE}, "onLast", $hash->{ONLAST} );
setReading( $hash->{DEVICE}, "onTotal", $hash->{ONTOTAL} );
setReading( $hash->{DEVICE}, "power", "0" );
setReading( $hash->{DEVICE}, "consumptionTotal",
$hash->{CONSUMPTIONTOTAL} );
}
else {
Log3 $hash->{DEVICE}, 3, "Keine Startzeit ermittelt";
}
}
#----- setReading -----#
sub setReading($$$) {
my ( $hash, $readingsName, $readingsWert ) = @_;
readingsBeginUpdate($hash);
readingsBulkUpdate( $hash, $readingsName, $readingsWert );
readingsEndUpdate( $hash, 1 );
}
1;
grüße
schau ins log was der grund ist.
oder auf der konsole auf der du fhem gestartet hast.
gruss
andre
Leider steht nichts im Log das sich auf das Modul bezieht. Nur das neustarten nach dem Absturz.
Edit:
Ich habs nochmal versucht. Dieses mal direkt in der Eingabezeile in fhemweb. Selbes Ergebnis:
2013.12.15 15:12:36.163 3: FS20 set wzDeckenfluter on
2013.12.15 15:12:36.847 1: Perfmon: possible freeze starting at 15:12:34, delay is 2.847
2013.12.15 15:12:45.518 1: Perfmon: possible freeze starting at 15:12:39, delay is 6.518
2013.12.15 15:12:50.803 1: Perfmon: possible freeze starting at 15:12:46, delay is 4.802
2013.12.15 15:13:40.131 1: Including fhem.cfg
Direkt nachdem mich den deckenfluter eingeschaltet hab hab ich in die adresszeile define sv_wzDeckenfluter currentCalculator wzDeckenfluter 9 60
kopiert, bestätigt, abgestürzt.
Die freeze's sind "normal" die hab ich ständig.
Hallo fhainz,
vielleicht hilft dir ja mein Betriebsstundenzähler weiter
http://www.fhemwiki.de/wiki/HourCounter (http://www.fhemwiki.de/wiki/HourCounter)
Über UserReadings kannst du beliebige Wert, also auch den Stromverbrauch über die Einschaltzeit berechnen lassen.
John
Hallo John,
den HourCounter hab ich mir schon angesehen. Habs mir auch teilweise zur Vorlage genommen aber leider blick ich nicht ganz durch den code.
Wahrscheinlich würde es mit deinem Modul auch irgendwie klappen, aber das bringt mir in meiner jetzigen Situation nicht. Ich will ja lernen wie man ein Modul schreibt.
Deshalb auch der "aufwand" etwas neu zu programmieren was es vielleicht in irgendeiner form schon gibt.
Grüße
setz mal
attr global verbose 5
bevor du das define absetzt.
Vll siehst Du dann besser, bis zu welcher Stelle das ganze kommt.
Vorher vll. noch Dein Prog mit
Log 1, cc: Zeile ###";
pflastern, damit Du sihest, was noch aufgerufen wurde und was nicht mehr.
Es könnte an der leeren set-routine liegen, denn fhemweb setzt zum Anzeigen des device ein "set <device> ?" ab, um die verfügbaren Befehle zurückzubekommen.
Wenn Du nur eine Variable belegst, funktioniert = @_
nicht, da musst Du shift nehmen.
Wird denn eine Fehlermeldung erzeugt, wenn Du ein reload Deines Moduls ausführst?
=8-)
starte vor allem fhem selber von hand auf der kommandozeile so das du ausgaben sehen kannst oder leite stdout und stderr um so das du beides auch im log hast.
my ($hash) = @_;
funktioniert auch mit einer variable. shift nur verwenden wenn du @_ auch tastächlich modifizieren willst.
gruss
andre
Ok habs num mit verbose 5 versucht.
Im Log steht folgendes:
Zitat2013.12.15 17:47:55.012 4: HTTP FHEMWEB:10.0.0.1:65154 GET /fhem&cmd=define+sv_wzDeckenfluter+currentCalculator+wzDeckenfluter+9+60
2013.12.15 17:47:55.017 5: Cmd: >define sv_wzDeckenfluter currentCalculator wzDeckenfluter 9 60<
2013.12.15 17:47:55.020 5: Loading ./FHEM/60_currentCalculator.pm
2013.12.15 17:47:55.078 5: Triggering global (1 changes)
2013.12.15 17:47:55.090 5: Notify loop for global DEFINED sv_wzDeckenfluter
2013.12.15 17:47:55.190 4: HTTP FHEMWEB:10.0.0.1:65154 GET /fhem?detail=sv_wzDeckenfluter
2013.12.15 17:49:22.531 1: Including fhem.cfg
Im Telnet Fenster hatte ich nur
Zitat2013-12-15 17:47:55.175 Global global DEFINED sv_wzDeckenfluter
Connection closed by foreign host.
Ich hab dann die Zeilen logs eingebaut. Ich komm bis zum return undef; in der sub currentCalculator_Define()
Hab direkt drunter noch ein Log und der wird nicht angezeigt.
Hilft das was?
Grüße
schau auf die konsole wenn du fhem von hand startest.
gruss
andre
Was meinst du mit von hand starten?
Nachdem abstürzen starte ich das raspi der sudo reboot neu.
also wenn fhem abschmiert musst du nicht den ganzen rechner neu starten.
irgendwo gibt es ein start script das fhem startet. das kannst du auch von hand starten. etwas in der art /etc/init.d/fhem start
je nach user vermutlich mit sudo. in diesem terminal in dem du das gemacht hast sollte beim absturz etwas zu sehen sein.
du kannst auch die zeile perl fhem.pl fhem.cfg
so ändern das stdout und stderr geloggt werden:perl fhem.pl fhem.cfg >>/opt/fhem/log/fhem-stdout 2>>/opt/fhem/log/fhem-stderr
gruss
andre
Zitat von: justme1968 am 15 Dezember 2013, 18:36:59also wenn fhem abschmiert musst du nicht den ganzen rechner neu starten.
Gut zu wissen ;) Das script ist in dem ordner den du beschrieben hast.
Zitat von: justme1968 am 15 Dezember 2013, 18:36:59in diesem terminal in dem du das gemacht hast sollte beim absturz etwas zu sehen sein.
Wann? Wenn ich dann per telnet eingeloggt bin?
Zitat von: justme1968 am 15 Dezember 2013, 18:36:59du kannst auch die zeile perl fhem.pl fhem.cfg
so ändern das stdout und stderr geloggt werden:perl fhem.pl fhem.cfg >>/opt/fhem/log/fhem-stdout 2>>/opt/fhem/log/fhem-stderr
Wo soll sich diese Zeile befinden?
Ich glaub ich steh am Schlauch :(
grüße
ja wenn du per ssh oder telnet verbunden bist.
die zeile ist in dem start script.
gruss
andre
Alles klar. Jetzt hab ich es überissen ;)
Wenn ich fhem so starte bekomm ich gleich jede menge Fehlermeldungen
Useless use of private variable in void context at ./FHEM/33_readingsGroup.pm line 525, <> line 8.
Use of uninitialized value $name in substitution (s///) at ./FHEM/01_FHEMWEB.pm line 1824.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in substitution (s///) at ./FHEM/01_FHEMWEB.pm line 1824.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in substitution (s///) at ./FHEM/01_FHEMWEB.pm line 1824.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in substitution (s///) at ./FHEM/01_FHEMWEB.pm line 1824.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in substitution (s///) at ./FHEM/01_FHEMWEB.pm line 1824.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in substitution (s///) at ./FHEM/01_FHEMWEB.pm line 1824.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in substitution (s///) at ./FHEM/01_FHEMWEB.pm line 1824.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in substitution (s///) at ./FHEM/01_FHEMWEB.pm line 1824.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in substitution (s///) at ./FHEM/01_FHEMWEB.pm line 1824.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Use of uninitialized value $name in hash element at ./FHEM/01_FHEMWEB.pm line 1826.
Undefined subroutine &main::currentCalculator_Get called at fhem.pl line 2636
Undefined subroutine kam direkt nachdem ich das define in der eingabezeile abgesetzt hab. Der rest gleich nach dem starten.
Eigenartig das der Fehler aussagt das ich keine currentCalculator_Get habe. Das hab ich ja mit $hash->{GetFn} = "currentCalculator_Get";
definiert oder?
grüße
du muss sie auch schreiben. nicht nur deklarieren.
gruss
andre
OK das hat jetzt geklappt aber nachdem die detail Seite angezeigt wurde hat sich fhem mit dem Fehler
ZitatCan't use string ("wzDeckenfluter") as a HASH ref while "strict refs" in use at ./FHEM/60_currentCalculator.pm line 96.
wieder aufgehängt ;)
Zeile 96:
$hash->{ON} = ReadingsVal( $hash->{DEVICE}, "on", "0" );
grüße
du übergibst beim aufruf von currentCalculator_Berechnen nicht $hash sondern $hash->{DEVICE}. das ist falsch. jedenfalls dann wenn du in currentCalculator_Berechnen einen $hash erwartest...
gruss
andre
Kannst du mir ein Beispiel schreiben wie es richtig ist?
Wie gesagt ist mein erstes Modul und eigentlich hab ich, durch mangel an developer einsteiger infos, keinen Plan was ich da mache ;)
grüße
versuch es mal nur mit $hash. aber es ist dein modul und ich kann nicht in deinen kopf schauen. es gibt kein einziges richtig sonder sehr viele möglichkeiten.
gruss
andre
vielleicht allgemein: es ist wichtig das du dein device (meistens $hash) und das device an das du dich dran hängst nicht durcheinander bringst.
du willst in fast allen routinen dein device übergeben und da einen link zum device das überwacht werden soll drine haben.
gruss
andre
Sry ich versteh's nicht.
Ich weiß nicht mal was was dieses $hash ist bzw. was es macht oder wie bzw. wann ich es einsetze
Soll ich anstatt $hash->{} "normale" variablen verwenden so wie in dem script das ich in der 99_myUtils.pm hatte?
#------------------------- Stromverbrauch nach Laufzeit ermitteln ---------------#
#----- Stromverbrauch -----#
sub stromverbrauch($$) {
my $device = shift;
my $watt = shift;
my $on = "";
my $off = 0;
my $onLast = 0;
my $consumptionLast = 0;
my $onTotal = 0;
my $consumptionTotal = 0;
#----- Untoggle Fix-----#
if ( Value($device) eq "toggle" ) {
if ( OldValue($device) eq "off" ) {
fhem("set $device on");
}
else {
fhem("set $device off");
}
}
if ( Value($device) eq "on" ) {
$on = int( time() );
setReading( $device, "on", $on );
setReading( $device, "power", $watt );
}
elsif ( Value($device) eq "off" ) {
stromverbrauchBerechnen( $device, $watt );
}
else {
Log3 $device, 3, "Untoggle Problem";
}
}
#----- Stromverbrauch berechnen -----#
sub stromverbrauchBerechnen($$) {
$device = shift;
$watt = shift;
$on = ReadingsVal( $device, "on", "0" );
$off = int( time() );
$onLast = $off - $on;
$onTotal = ReadingsVal( $device, "onTotal", "0" );
$consumptionTotal = ReadingsVal( $device, "consumptionTotal", "" );
$onTotal = int( $onTotal + $onLast );
$consumptionLast = $onLast * $watt / 1000 / 3600;
$consumptionTotal = $consumptionTotal + $consumptionLast;
$consumptionTotal = sprintf "%.2f", $consumptionTotal;
if ( $on > 0 ) {
setReading( $device, "on", 0 );
setReading( $device, "off", $off );
setReading( $device, "onLast", $onLast );
setReading( $device, "onTotal", $onTotal );
setReading( $device, "power", "0" );
setReading( $device, "consumptionTotal", $consumptionTotal );
}
else {
Log3 $device, 3, "Keine Startzeit ermittelt";
}
}
#----- setReading -----#
sub setReading($$$) {
my $device = shift;
my $readingsName = shift;
my $readingsWert = shift;
readingsBeginUpdate( $main::defs{$device} );
readingsBulkUpdate( $main::defs{$device}, $readingsName, $readingsWert );
readingsBulkUpdate( $main::defs{$device}, $readingsName, $readingsWert );
readingsEndUpdate( $main::defs{$device}, 1 );
}
Grüße
Ich hab jetzt das Modul nochmals umgebaut und es funktioniert schon so halbwegs.
Mein Problem ist jetzt, dass das die currentCalculator_NotifyFn sich in einer endlosschleife andauernd aufruft.
Schaff ich es irgendwie das sich das notifyFn nur aufruft wenn das entsprechende device on ist und sich solang alle interval Sekunden wiederholt bis das device off ist?
Hier mein Code:
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday sleep);
sub currentCalculator_Initialize($) {
my ($hash) = @_;
$hash->{GetFn} = "currentCalculator_Get";
$hash->{SetFn} = "currentCalculator_Set";
$hash->{DefFn} = "currentCalculator_Define";
$hash->{UndefFn} = "currentCalculator_Undefine";
$hash->{NotifyFn} = "currentCalculator_NotifyFn";
}
#####################################
sub currentCalculator_Define($$) {
my ( $hash, $def ) = @_;
my @a = split( "[ \t][ \t]*", $def );
return "Usage: define <name> currentCalculator [device] [watt] [invterval]"
if ( @a < 4 || @a > 5 );
my $name = $a[0];
my $device = $a[2];
my $watt = $a[3];
my $interval = 60;
$interval = $a[4] if ( $interval < 60 );
$hash->{NAME} = $name;
$hash->{DEVICE} = $device;
$hash->{STATE} = "Active";
$hash->{INTERVAL} = $interval;
$hash->{WATT} = $watt;
Log3 $name, 3, "cc: Zeile 38";
return undef;
}
sub currentCalculator_Set() {}
sub currentCalculator_Get() {}
sub currentCalculator_Undefine($) {
my ($hash) = @_;
RemoveInternalTimer($hash->{NAME});
return undef;
}
sub currentCalculator_NotifyFn($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
#----- Untoggle Fix-----#
if ( Value( $device ) eq "toggle" ) {
if ( OldValue( $device ) eq "off" ) {
fhem("set $device on");
}
else {
fhem("set $device off");
}
}
Log3 $name, 3, "cc: Zeile 67";
my $on = "";
if( Value($device) eq "on" ) {
$on = int( time() );
Log3 $name, 3, "cc: Zeile 73";
setReading( $device, "on", $on );
setReading( $device, "power", $watt );
Log3 $name, 3, "cc: Zeile 76";
}
elsif ( Value($device) eq "off" ) {
currentCalculator_Berechnen( $hash, $device, $watt );
}
else {
Log3 $name, 3, "Untoggle Problem";
}
Log3 $name, 3, "cc: Zeile 84";
return undef;
RemoveInternalTimer($hash->{NAME});
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "currentCalculator_NotifyFn",$hash, 0);
}
#----- Stromverbrauch berechnen -----#
sub currentCalculator_Berechnen($$$) {
my ($hash) = @_;
my $device = shift;
my $watt = shift;
Log3 $device, 3, "cc: Zeile 98";
my $on = "";
my $off = 0;
my $onLast = 0;
my $consumptionLast = 0;
my $onTotal = 0;
my $consumptionTotal = 0;
$on = ReadingsVal( $device, "on", "0" );
$off = int( time() );
$onLast = $off - $on;
$onTotal = ReadingsVal( $device, "onTotal", "0" );
$consumptionTotal = ReadingsVal( $device, "consumptionTotal", "0" );
$onTotal = int( $onTotal + $onLast );
$consumptionLast = $onLast * $watt / 1000 / 3600;
$consumptionTotal = $consumptionTotal + $consumptionLast;
$consumptionTotal = sprintf "%.2f", $consumptionTotal;
Log3 $device, 3, "cc: Zeile 121";
Log3 $device, 3, "Device:".$device.", On:".$on.", Off:".$off;
if ( $on > 0 ) {
setReading( $device, "on", 0 );
setReading( $device, "off", $off );
setReading( $device, "onLast", $onLast );
setReading( $device, "onTotal", $onTotal );
setReading( $device, "power", "0" );
setReading( $device, "consumptionTotal", $consumptionTotal );
}
else {
Log3 $device, 3, "Keine Startzeit ermittelt";
}
Log3 $device, 3, "cc: Zeile 134";
}
#----- setReading -----#
sub setReading($$$) {
my $device = shift;
my $readingsName = shift;
my $readingsWert = shift;
Log3 $device, 3, "cc: Zeile 143";
readingsBeginUpdate($main::defs{$device});
readingsBulkUpdate( $main::defs{$device}, $readingsName, $readingsWert );
readingsEndUpdate( $main::defs{$device}, 1 );
}
1;
Log:
2013.12.29 18:43:48.089 3: Device:HASH(0x21e21f8), On:0, Off:1388339028
2013.12.29 18:43:48.089 3: Keine Startzeit ermittelt
2013.12.29 18:43:48.090 3: cc: Zeile 134
2013.12.29 18:43:48.091 3: cc: Zeile 84
2013.12.29 18:43:48.484 3: cc: Zeile 67
2013.12.29 18:43:48.485 3: cc: Zeile 98
2013.12.29 18:43:48.488 3: cc: Zeile 121
2013.12.29 18:43:48.489 3: Device:HASH(0x21e21f8), On:0, Off:1388339028
2013.12.29 18:43:48.490 3: Keine Startzeit ermittelt
2013.12.29 18:43:48.491 3: cc: Zeile 134
2013.12.29 18:43:48.492 3: cc: Zeile 84
2013.12.29 18:43:48.883 3: cc: Zeile 67
2013.12.29 18:43:48.884 3: cc: Zeile 98
2013.12.29 18:43:48.887 3: cc: Zeile 121
2013.12.29 18:43:48.888 3: Device:HASH(0x21e21f8), On:0, Off:1388339028
2013.12.29 18:43:48.889 3: Keine Startzeit ermittelt
2013.12.29 18:43:48.890 3: cc: Zeile 134
2013.12.29 18:43:48.891 3: cc: Zeile 84
2013.12.29 18:43:55.097 3: cc: Zeile 67
2013.12.29 18:43:55.098 3: cc: Zeile 98
2013.12.29 18:43:55.101 3: cc: Zeile 121
Grüße
du solltest für notify und für den timer zwei unterschiedliche funktionen verwenden. und am besten noch eine update funktion die die werte aktualisiert.
currentCalculator_NotifyFn nur um festzustellen ob dein device den zustand gewechselt hat und eine andere funktion die regelnässig aufgerufen wird solange dein device an ist. also sobald das überwachte device auf on geht die timer funktion ein mal aufrufen. in der timer funktion die update aufrufen und das RemoveInternalTimer / InternalTimer und wenn dein device auf off geht ein mal ein RemoveInternalTimer und update.
gruss
andre
ok ich hab jetzt noch eine Funktion run. Die Funktion setzt die startzeit und ruft per timer die berechnen() auf, diese wiederum die setReading().
Leider immer noch in einer endlosschleife und nun wird auch $device nicht mehr an die Funktion setReading übergeben. :(
Code:
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday sleep);
sub currentCalculator_Initialize($) {
my ($hash) = @_;
$hash->{GetFn} = "currentCalculator_Get";
$hash->{SetFn} = "currentCalculator_Set";
$hash->{DefFn} = "currentCalculator_Define";
$hash->{UndefFn} = "currentCalculator_Undefine";
$hash->{NotifyFn} = "currentCalculator_NotifyFn";
}
#####################################
sub currentCalculator_Define($$) {
my ( $hash, $def ) = @_;
my @a = split( "[ \t][ \t]*", $def );
return "Usage: define <name> currentCalculator [device] [watt] [invterval]"
if ( @a < 4 || @a > 5 );
my $name = $a[0];
my $device = $a[2];
my $watt = $a[3];
my $interval = 60;
$interval = $a[4] if ( $interval < 60 );
$hash->{NAME} = $name;
$hash->{DEVICE} = $device;
$hash->{STATE} = "Active";
$hash->{INTERVAL} = $interval;
$hash->{WATT} = $watt;
Log3 $name, 3, "cc: Zeile 38";
return undef;
}
sub currentCalculator_Set() {}
sub currentCalculator_Get() {}
sub currentCalculator_Undefine($) {
my ($hash) = @_;
RemoveInternalTimer($hash->{NAME});
return undef;
}
sub currentCalculator_NotifyFn($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
#----- Untoggle Fix-----#
if ( Value( $device ) eq "toggle" ) {
if ( OldValue( $device ) eq "off" ) {
fhem("set $device on");
}
else {
fhem("set $device off");
}
}
my $on = "";
if( Value($device) eq "on" ) {
currentCalculator_Run($hash,$device,$watt);
}
elsif ( Value($device) eq "off" ) {
currentCalculator_Berechnen( $hash, $device, $watt );
setReading( $device, "on", 0 );
RemoveInternalTimer($hash->{NAME});
}
else {
Log3 $name, 3, "Untoggle Problem";
}
return undef;
}
#----- Stromverbrauch Startzeit setzen -----#
sub currentCalculator_Run($$$){
my ($hash) = @_;
my $device = shift;
my $watt = shift;
my $on = int( time() );
setReading( $device, "on", $on );
setReading( $device, "power", $watt );
currentCalculator_Berechnen($hash,$device,$watt);
RemoveInternalTimer($hash->{NAME});
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "currentCalculator_Berechnen",$hash, 0);
}
#----- Stromverbrauch berechnen -----#
sub currentCalculator_Berechnen($$$) {
my ($hash) = @_;
my $device = shift;
my $watt = shift;
my $on = "";
my $off = 0;
my $onLast = 0;
my $consumptionLast = 0;
my $onTotal = 0;
my $consumptionTotal = 0;
$on = ReadingsVal( $device, "on", "0" );
$off = int( time() );
$onLast = $off - $on;
$onTotal = ReadingsVal( $device, "onTotal", "0" );
$consumptionTotal = ReadingsVal( $device, "consumptionTotal", "0" );
$onTotal = int( $onTotal + $onLast );
$consumptionLast = $onLast * $watt / 1000 / 3600;
$consumptionTotal = $consumptionTotal + $consumptionLast;
$consumptionTotal = sprintf "%.2f", $consumptionTotal;
Log3 $device, 3, "Device:".$device.", On:".$on.", Off:".$off;
setReading( $device, "on", $on );
setReading( $device, "off", $off );
setReading( $device, "onLast", $onLast );
setReading( $device, "onTotal", $onTotal );
setReading( $device, "power", "0" );
setReading( $device, "consumptionTotal", $consumptionTotal );
}
#----- setReading -----#
sub setReading($$$) {
my $device = shift;
my $readingsName = shift;
my $readingsWert = shift;
Log3 $device, 3, "cc: Zeile 143";
readingsBeginUpdate($main::defs{$device});
readingsBulkUpdate( $main::defs{$device}, $readingsName, $readingsWert );
readingsEndUpdate( $main::defs{$device}, 1 );
}
1;
Log:
2013.12.29 19:40:50.541 3: cc: Zeile 38
2013.12.29 19:40:59.913 3: Device:HASH(0x18b23e0), On:0, Off:1388342459
2013.12.29 19:40:59.914 3: cc: Zeile 143
2013.12.29 19:40:59.918 1: readingsUpdate(,on,0) missed to call readingsBeginUpdate first.
2013.12.29 19:40:59.922 3: cc: Zeile 143
2013.12.29 19:40:59.926 1: readingsUpdate(,off,1388342459) missed to call readingsBeginUpdate first.
2013.12.29 19:40:59.929 3: cc: Zeile 143
2013.12.29 19:40:59.933 1: readingsUpdate(,onLast,1388342459) missed to call readingsBeginUpdate first.
2013.12.29 19:40:59.936 3: cc: Zeile 143
2013.12.29 19:40:59.939 1: readingsUpdate(,onTotal,1388342459) missed to call readingsBeginUpdate first.
2013.12.29 19:40:59.942 3: cc: Zeile 143
2013.12.29 19:40:59.945 1: readingsUpdate(,power,0) missed to call readingsBeginUpdate first.
2013.12.29 19:40:59.948 3: cc: Zeile 143
2013.12.29 19:40:59.952 1: readingsUpdate(,consumptionTotal,0.00) missed to call readingsBeginUpdate first.
2013.12.29 19:40:59.954 3: cc: Zeile 143
2013.12.29 19:41:00.139 3: Device:HASH(0x18b23e0), On:0, Off:1388342460
2013.12.29 19:41:00.140 3: cc: Zeile 143
2013.12.29 19:41:00.143 1: readingsUpdate(,on,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.146 3: cc: Zeile 143
2013.12.29 19:41:00.150 1: readingsUpdate(,off,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.154 3: cc: Zeile 143
2013.12.29 19:41:00.158 1: readingsUpdate(,onLast,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.163 3: cc: Zeile 143
2013.12.29 19:41:00.167 1: readingsUpdate(,onTotal,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.171 3: cc: Zeile 143
2013.12.29 19:41:00.175 1: readingsUpdate(,power,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.179 3: cc: Zeile 143
2013.12.29 19:41:00.183 1: readingsUpdate(,consumptionTotal,0.00) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.187 3: cc: Zeile 143
2013.12.29 19:41:00.259 3: Device:HASH(0x18b23e0), On:0, Off:1388342460
2013.12.29 19:41:00.260 3: cc: Zeile 143
2013.12.29 19:41:00.263 1: readingsUpdate(,on,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.267 3: cc: Zeile 143
2013.12.29 19:41:00.271 1: readingsUpdate(,off,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.274 3: cc: Zeile 143
2013.12.29 19:41:00.278 1: readingsUpdate(,onLast,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.281 3: cc: Zeile 143
2013.12.29 19:41:00.284 1: readingsUpdate(,onTotal,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.288 3: cc: Zeile 143
2013.12.29 19:41:00.292 1: readingsUpdate(,power,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.295 3: cc: Zeile 143
2013.12.29 19:41:00.299 1: readingsUpdate(,consumptionTotal,0.00) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.303 3: cc: Zeile 143
2013.12.29 19:41:00.382 3: Device:HASH(0x18b23e0), On:0, Off:1388342460
2013.12.29 19:41:00.383 3: cc: Zeile 143
2013.12.29 19:41:00.386 1: readingsUpdate(,on,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.390 3: cc: Zeile 143
2013.12.29 19:41:00.393 1: readingsUpdate(,off,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.397 3: cc: Zeile 143
2013.12.29 19:41:00.400 1: readingsUpdate(,onLast,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.404 3: cc: Zeile 143
2013.12.29 19:41:00.408 1: readingsUpdate(,onTotal,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.411 3: cc: Zeile 143
2013.12.29 19:41:00.415 1: readingsUpdate(,power,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.418 3: cc: Zeile 143
2013.12.29 19:41:00.422 1: readingsUpdate(,consumptionTotal,0.00) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.426 3: cc: Zeile 143
2013.12.29 19:41:00.583 3: Device:HASH(0x18b23e0), On:0, Off:1388342460
2013.12.29 19:41:00.585 3: cc: Zeile 143
2013.12.29 19:41:00.588 1: readingsUpdate(,on,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.591 3: cc: Zeile 143
2013.12.29 19:41:00.595 1: readingsUpdate(,off,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.598 3: cc: Zeile 143
2013.12.29 19:41:00.602 1: readingsUpdate(,onLast,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.605 3: cc: Zeile 143
2013.12.29 19:41:00.609 1: readingsUpdate(,onTotal,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.613 3: cc: Zeile 143
2013.12.29 19:41:00.616 1: readingsUpdate(,power,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.620 3: cc: Zeile 143
2013.12.29 19:41:00.623 1: readingsUpdate(,consumptionTotal,0.00) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.627 3: cc: Zeile 143
2013.12.29 19:41:00.694 3: Device:HASH(0x18b23e0), On:0, Off:1388342460
2013.12.29 19:41:00.695 3: cc: Zeile 143
2013.12.29 19:41:00.698 1: readingsUpdate(,on,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.702 3: cc: Zeile 143
2013.12.29 19:41:00.705 1: readingsUpdate(,off,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.709 3: cc: Zeile 143
2013.12.29 19:41:00.713 1: readingsUpdate(,onLast,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.716 3: cc: Zeile 143
2013.12.29 19:41:00.720 1: readingsUpdate(,onTotal,1388342460) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.723 3: cc: Zeile 143
2013.12.29 19:41:00.727 1: readingsUpdate(,power,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.731 3: cc: Zeile 143
2013.12.29 19:41:00.734 1: readingsUpdate(,consumptionTotal,0.00) missed to call readingsBeginUpdate first.
2013.12.29 19:41:00.738 3: cc: Zeile 143
2013.12.29 19:41:03.419 3: Device:HASH(0x18b23e0), On:0, Off:1388342463
2013.12.29 19:41:03.420 3: cc: Zeile 143
2013.12.29 19:41:03.424 1: readingsUpdate(,on,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:03.427 3: cc: Zeile 143
2013.12.29 19:41:03.430 1: readingsUpdate(,off,1388342463) missed to call readingsBeginUpdate first.
2013.12.29 19:41:03.434 3: cc: Zeile 143
2013.12.29 19:41:03.436 1: readingsUpdate(,onLast,1388342463) missed to call readingsBeginUpdate first.
2013.12.29 19:41:03.439 3: cc: Zeile 143
2013.12.29 19:41:03.442 1: readingsUpdate(,onTotal,1388342463) missed to call readingsBeginUpdate first.
2013.12.29 19:41:03.444 3: cc: Zeile 143
2013.12.29 19:41:03.447 1: readingsUpdate(,power,0) missed to call readingsBeginUpdate first.
2013.12.29 19:41:03.450 3: cc: Zeile 143
2013.12.29 19:41:03.453 1: readingsUpdate(,consumptionTotal,0.00) missed to call readingsBeginUpdate first.
2013.12.29 19:41:03.455 3: cc: Zeile 143
2013.12.29 19:41:03.627 3: Device:HASH(0x18b23e0), On:0, Off:1388342463
2013.12.29 19:41:03.628 3: cc: Zeile 143
2013.12.29 19:41:03.632 1: readingsUpdate(,on,0) missed to call readingsBeginUpdate first.
Ich raff es nicht... :(
Grüße
die NotifyFn wird für jedes event in fhem aufgerufen.
du darfst nur darauf reagieren wenn es auch dein device betrifft. und nur auf on und off und delete.
sonst hat du ein run für wirklich jedes event das in fhem passiert getriggert.
gruss
andre
Zitat von: justme1968 am 29 Dezember 2013, 19:59:16
du darfst nur darauf reagieren wenn es auch dein device betrifft. und nur auf on und off und delete.
ich hab mir jetzt ein paar module mit einer notifyfn angesehen. Meinst du sowas wie
return if($dev->{NAME} eq $name);
in deiner readingsGroup.pm?
Ich komm nicht drauf..
Grüße
so ähnlich aber das alleine reicht nicht. das ignoriert nur notifys die für den currentCalculator. du willst aber alles ignorieren bis auf die notifys für das device an dem der currentCalculator hängt. also eher so:return if($dev->{NAME} ne $hash->{DEVICE});
gruss
andre
OK, das funktioniert nun auch.
Nach einige male Haare raufen und ca. 100x fhem neu starten sieht mein Modul nun so aus
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday sleep);
sub currentCalculator_Initialize($) {
my ($hash) = @_;
$hash->{GetFn} = "currentCalculator_Get";
$hash->{SetFn} = "currentCalculator_Set";
$hash->{DefFn} = "currentCalculator_Define";
$hash->{UndefFn} = "currentCalculator_Undefine";
$hash->{NotifyFn} = "currentCalculator_NotifyFn";
}
#####################################
sub currentCalculator_Define($$) {
my ( $hash, $def ) = @_;
my $version = "0.1";
my @a = split( "[ \t][ \t]*", $def );
return "Usage: define <name> currentCalculator [device] [watt] [invterval]"
if ( @a < 4 || @a > 5 );
my $name = $a[0];
my $device = $a[2];
my $watt = $a[3];
my $interval = 60;
$interval = $a[4] if ( $interval < 60 );
$hash->{NAME} = $name;
$hash->{DEVICE} = $device;
$hash->{STATE} = "Active";
$hash->{INTERVAL} = $interval;
$hash->{WATT} = $watt;
Log3 $name, 3, "[currentCalculator v".$version." initialisiert]";
return undef;
}
sub currentCalculator_Set() {}
sub currentCalculator_Get() {}
sub currentCalculator_Undefine($) {
my ($hash) = @_;
RemoveInternalTimer($hash->{NAME});
return undef;
}
sub currentCalculator_NotifyFn($$) {
my ( $hash, $dev ) = @_;
return if($dev->{NAME} ne $hash->{DEVICE});
my $name = $hash->{NAME};
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
#----- Untoggle Fix-----#
if ( Value( $device ) eq "toggle" ) {
if ( OldValue( $device ) eq "off" ) {
fhem("set $device on");
}
else {
fhem("set $device off");
}
}
my $on = "";
if( Value($device) eq "on" ) {
currentCalculator_Run($hash);
}
elsif ( Value($device) eq "off" ) {
currentCalculator_Berechnen( $hash, $device, $watt );
currentCalculator_setReading( $device, "on", 0 );
currentCalculator_setReading( $device, "watt", 0 );
RemoveInternalTimer($hash->{NAME});
}
else {
Log3 $name, 3, "Untoggle Problem";
}
return undef;
}
#----- Stromverbrauch Startzeit setzen -----#
sub currentCalculator_Run($){
my ($hash) = @_;
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
#Log3 $device, 3, "device:".$device.", Watt:".$watt.", cc_Run";
my $on = int( time() );
currentCalculator_setReading( $device, "on", $on );
currentCalculator_setReading( $device, "power", $watt );
currentCalculator_Berechnen($hash,$device,$watt);
RemoveInternalTimer($hash->{NAME});
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "currentCalculator_Berechnen",$hash, 0);
Log3 $device, 3, "[currentCalculator] cc_Run";
}
#----- Stromverbrauch berechnen -----#
sub currentCalculator_Berechnen($$$) {
my ($hash) = @_;
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
my $on = "";
my $off = 0;
my $onLast = 0;
my $consumptionLast = 0;
my $onTotal = 0;
my $consumptionTotal = 0;
Log3 $device, 3, "[currentCalculator] cc_Berechnen";
$on = ReadingsVal( $device, "on", "0" );
$off = int( time() );
$onLast = $off - $on;
$onTotal = ReadingsVal( $device, "onTotal", "0" );
$consumptionTotal = ReadingsVal( $device, "consumptionTotal", "0" );
$onTotal = int( $onTotal + $onLast );
$consumptionLast = $onLast * $watt / 1000 / 3600;
$consumptionTotal = $consumptionTotal + $consumptionLast;
$consumptionTotal = sprintf "%.2f", $consumptionTotal;
#Log3 $device, 3, "Device:".$device.", On:".$on.", Off:".$off;
currentCalculator_setReading( $device, "on", $on );
currentCalculator_setReading( $device, "off", $off );
currentCalculator_setReading( $device, "onLast", $onLast );
currentCalculator_setReading( $device, "onTotal", $onTotal );
currentCalculator_setReading( $device, "power", "0" );
currentCalculator_setReading( $device, "consumptionTotal", $consumptionTotal );
}
#----- setReading -----#
#Log3 $device, 3, "device:".$device.", readingsName:".$readingsName.", readingsWert:".$readingsName.", cc_setReading";
sub currentCalculator_setReading($$$) {
my $device = shift;
my $readingsName = shift;
my $readingsWert = shift;
Log3 $device, 3, "[currentCalculator] cc_setReading";
readingsBeginUpdate($main::defs{$device});
readingsBulkUpdate( $main::defs{$device}, $readingsName, $readingsWert );
readingsEndUpdate( $main::defs{$device}, 1 );
}
1;
Wenn ich nun das "überwachte" device on schalte werden die readings gesetzt und 1 min pausiert. Bis hier hin passt's. Ab der 2. minute gehts aber wieder rund, sprich endlosschleife.
2013.12.29 23:15:46.655 3: [currentCalculator v0.1 initialisiert]
2013.12.29 23:16:11.539 3: FS20 set wzDeckenfluter on
2013.12.29 23:16:11.820 3: [currentCalculator] cc_setReading
2013.12.29 23:16:11.823 3: [currentCalculator] cc_setReading
2013.12.29 23:16:11.826 3: [currentCalculator] cc_Berechnen
2013.12.29 23:16:11.828 3: [currentCalculator] cc_setReading
2013.12.29 23:16:11.832 3: [currentCalculator] cc_setReading
2013.12.29 23:16:11.835 3: [currentCalculator] cc_setReading
2013.12.29 23:16:11.838 3: [currentCalculator] cc_setReading
2013.12.29 23:16:11.842 3: [currentCalculator] cc_setReading
2013.12.29 23:16:11.845 3: [currentCalculator] cc_setReading
2013.12.29 23:16:11.849 3: [currentCalculator] cc_Run
2013.12.29 23:17:11.854 3: [currentCalculator] cc_Berechnen
2013.12.29 23:17:11.856 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.106 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.109 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.112 3: [currentCalculator] cc_Berechnen
2013.12.29 23:17:12.114 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.117 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.120 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.123 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.127 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.130 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.134 3: [currentCalculator] cc_Run
2013.12.29 23:17:12.210 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.432 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.435 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.438 3: [currentCalculator] cc_Berechnen
2013.12.29 23:17:12.439 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.442 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.445 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.448 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.451 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.454 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.458 3: [currentCalculator] cc_Run
2013.12.29 23:17:12.529 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.747 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.750 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.753 3: [currentCalculator] cc_Berechnen
2013.12.29 23:17:12.754 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.758 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.761 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.763 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.766 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.769 3: [currentCalculator] cc_setReading
2013.12.29 23:17:12.773 3: [currentCalculator] cc_Run
2013.12.29 23:17:12.847 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.056 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.060 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.062 3: [currentCalculator] cc_Berechnen
2013.12.29 23:17:13.064 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.067 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.070 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.072 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.075 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.078 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.082 3: [currentCalculator] cc_Run
2013.12.29 23:17:13.154 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.365 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.368 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.371 3: [currentCalculator] cc_Berechnen
2013.12.29 23:17:13.373 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.376 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.379 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.381 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.384 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.387 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.391 3: [currentCalculator] cc_Run
2013.12.29 23:17:13.464 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.672 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.675 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.677 3: [currentCalculator] cc_Berechnen
2013.12.29 23:17:13.679 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.682 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.686 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.689 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.691 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.694 3: [currentCalculator] cc_setReading
2013.12.29 23:17:13.698 3: [currentCalculator] cc_Run
Woran kann das liegen?
Grüße
du darfst das run nur aufrufen wenn dein device von off auf on wechselt. sonst nicht.
du rufst es bei jedem notify auf das dein device betrifft. also auch z.b. wenn nach der ersten minute das verbrauchs reading geschrieben wird.
gruss
andre
Zitat von: justme1968 am 29 Dezember 2013, 23:30:42
du darfst das run nur aufrufen wenn dein device von off auf on wechselt. sonst nicht.
currentCalculator_Run wird nur hier aufgerufen:
if( Value($device) eq "on" ) {
currentCalculator_Run($hash);
}
Grüße
ja. immer wenn das device on ist. du darfst es aber nur genau dann ein mal aufrufen wenn es eingeschaltet wird. nicht wenn es schon an ist.
Ok, klar die notifyFn wird ja immer aufgerufen.
Wie schaff ich es zu prüfen ob die run schonmal gelaufen ist? Ein reading setzen das run auf 1 setzt und das jedes mal abfragen? Da gibts sicher ne einfachere Lösung oder?
Grüße
es muss kein reading sein. eine interne Variable reicht. z.b. $hash->{running}
du kannst aber auch schauen ob das device vorher aus war.
gruss
andre
Jetzt werden nach 2 Wiederholung keine Readings mehr gesetzt. Vermute mal das Modul stoppt irgendwie. Fehler gibts keinen. Hast du noch eine Idee?
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday sleep);
sub currentCalculator_Initialize($) {
my ($hash) = @_;
$hash->{GetFn} = "currentCalculator_Get";
$hash->{SetFn} = "currentCalculator_Set";
$hash->{DefFn} = "currentCalculator_Define";
$hash->{UndefFn} = "currentCalculator_Undefine";
$hash->{NotifyFn} = "currentCalculator_NotifyFn";
}
#####################################
sub currentCalculator_Define($$) {
my ( $hash, $def ) = @_;
my $version = "0.1";
my @a = split( "[ \t][ \t]*", $def );
return "Usage: define <name> currentCalculator [device] [watt] [invterval]"
if ( @a < 4 || @a > 5 );
my $name = $a[0];
my $device = $a[2];
my $watt = $a[3];
my $interval = 60;
$interval = $a[4] if ( $interval < 60 );
$hash->{NAME} = $name;
$hash->{DEVICE} = $device;
$hash->{STATE} = "Active";
$hash->{INTERVAL} = $interval;
$hash->{WATT} = $watt;
Log3 $name, 3, "[currentCalculator v".$version." initialisiert]";
return undef;
}
sub currentCalculator_Set() {}
sub currentCalculator_Get() {}
sub currentCalculator_Undefine($) {
my ($hash) = @_;
RemoveInternalTimer($hash->{NAME});
return undef;
}
sub currentCalculator_NotifyFn($$) {
my ( $hash, $dev ) = @_;
return if($dev->{NAME} ne $hash->{DEVICE});
my $name = $hash->{NAME};
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
#----- Untoggle Fix-----#
if ( Value( $device ) eq "toggle" ) {
if ( OldValue( $device ) eq "off" ) {
fhem("set $device on");
}
else {
fhem("set $device off");
}
}
my $on = "";
if( Value($device) eq "on") {
if( $hash->{running} <= 0)
{
$hash->{running} = 1;
currentCalculator_Run($hash);
}
}
elsif ( Value($device) eq "off" ) {
currentCalculator_Berechnen( $hash, $device, $watt );
currentCalculator_setReading( $device, "on", 0 );
currentCalculator_setReading( $device, "power", 0 );
RemoveInternalTimer($hash->{NAME});
$hash->{running} = 0;
}
else {
Log3 $name, 3, "Untoggle Problem";
}
return undef;
}
#----- Stromverbrauch Startzeit setzen -----#
sub currentCalculator_Run($){
my ($hash) = @_;
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
#Log3 $device, 3, "device:".$device.", Watt:".$watt.", cc_Run";
my $on = int( time() );
currentCalculator_setReading( $device, "on", $on );
currentCalculator_setReading( $device, "power", $watt );
currentCalculator_Berechnen($hash,$device,$watt);
RemoveInternalTimer($hash->{NAME});
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "currentCalculator_Berechnen",$hash, 0);
Log3 $device, 3, "[currentCalculator] cc_Run";
}
#----- Stromverbrauch berechnen -----#
sub currentCalculator_Berechnen($$$) {
my ($hash) = @_;
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
my $on = "";
my $off = 0;
my $onLast = 0;
my $consumptionLast = 0;
my $onTotal = 0;
my $consumptionTotal = 0;
Log3 $device, 3, "[currentCalculator] cc_Berechnen";
$on = ReadingsVal( $device, "on", "0" );
$off = int( time() );
$onLast = $off - $on;
$onTotal = ReadingsVal( $device, "onTotal", "0" );
$consumptionTotal = ReadingsVal( $device, "consumptionTotal", "0" );
$onTotal = int( $onTotal + $onLast );
$consumptionLast = $onLast * $watt / 1000 / 3600;
$consumptionTotal = $consumptionTotal + $consumptionLast;
$consumptionTotal = sprintf "%.2f", $consumptionTotal;
#Log3 $device, 3, "Device:".$device.", On:".$on.", Off:".$off;
currentCalculator_setReading( $device, "on", $on );
currentCalculator_setReading( $device, "off", $off );
currentCalculator_setReading( $device, "onLast", $onLast );
currentCalculator_setReading( $device, "onTotal", $onTotal );
currentCalculator_setReading( $device, "consumptionTotal", $consumptionTotal );
}
#----- setReading -----#
#Log3 $device, 3, "device:".$device.", readingsName:".$readingsName.", readingsWert:".$readingsName.", cc_setReading";
sub currentCalculator_setReading($$$) {
my $device = shift;
my $readingsName = shift;
my $readingsWert = shift;
Log3 $device, 3, "[currentCalculator] cc_setReading";
readingsBeginUpdate($main::defs{$device});
readingsBulkUpdate( $main::defs{$device}, $readingsName, $readingsWert );
readingsEndUpdate( $main::defs{$device}, 1 );
}
1;
2013.12.30 00:20:11.775 3: FS20 set wzDeckenfluter on
2013.12.30 00:20:11.989 3: [currentCalculator] cc_setReading
2013.12.30 00:20:11.992 3: [currentCalculator] cc_setReading
2013.12.30 00:20:11.994 3: [currentCalculator] cc_Berechnen
2013.12.30 00:20:11.996 3: [currentCalculator] cc_setReading
2013.12.30 00:20:11.999 3: [currentCalculator] cc_setReading
2013.12.30 00:20:12.001 3: [currentCalculator] cc_setReading
2013.12.30 00:20:12.004 3: [currentCalculator] cc_setReading
2013.12.30 00:20:12.007 3: [currentCalculator] cc_setReading
2013.12.30 00:20:12.011 3: [currentCalculator] cc_Run
2013.12.30 00:21:12.014 3: [currentCalculator] cc_Berechnen
2013.12.30 00:21:12.016 3: [currentCalculator] cc_setReading
2013.12.30 00:21:12.344 3: [currentCalculator] cc_setReading
2013.12.30 00:21:12.622 3: [currentCalculator] cc_setReading
2013.12.30 00:21:12.887 3: [currentCalculator] cc_setReading
2013.12.30 00:21:13.153 3: [currentCalculator] cc_setReading
2013.12.30 00:25:06.313 3: FS20 set wzDeckenfluter on
2013.12.30 00:25:29.827 3: FS20 set wzDeckenfluter off
2013.12.30 00:25:30.103 3: [currentCalculator] cc_Berechnen
2013.12.30 00:25:30.105 3: [currentCalculator] cc_setReading
2013.12.30 00:25:30.108 3: [currentCalculator] cc_setReading
2013.12.30 00:25:30.111 3: [currentCalculator] cc_setReading
2013.12.30 00:25:30.115 3: [currentCalculator] cc_setReading
2013.12.30 00:25:30.118 3: [currentCalculator] cc_setReading
2013.12.30 00:25:30.121 3: [currentCalculator] cc_setReading
2013.12.30 00:25:30.124 3: [currentCalculator] cc_setReading
2013.12.30 00:25:37.519 3: FS20 set wzDeckenfluter on
2013.12.30 00:25:37.767 3: [currentCalculator] cc_setReading
2013.12.30 00:25:37.770 3: [currentCalculator] cc_setReading
2013.12.30 00:25:37.773 3: [currentCalculator] cc_Berechnen
2013.12.30 00:25:37.774 3: [currentCalculator] cc_setReading
2013.12.30 00:25:37.777 3: [currentCalculator] cc_setReading
2013.12.30 00:25:37.780 3: [currentCalculator] cc_setReading
2013.12.30 00:25:37.783 3: [currentCalculator] cc_setReading
2013.12.30 00:25:37.786 3: [currentCalculator] cc_setReading
2013.12.30 00:25:37.789 3: [currentCalculator] cc_Run
2013.12.30 00:26:37.800 3: [currentCalculator] cc_Berechnen
2013.12.30 00:26:37.801 3: [currentCalculator] cc_setReading
2013.12.30 00:26:38.118 3: [currentCalculator] cc_setReading
2013.12.30 00:26:38.423 3: [currentCalculator] cc_setReading
2013.12.30 00:26:38.689 3: [currentCalculator] cc_setReading
2013.12.30 00:26:38.958 3: [currentCalculator] cc_setReading
Grüße
hatte ich dir das eigentlich schon gezeigt: http://www.fhemwiki.de/wiki/HourCounter ?
wenn es nicht schon macht was du willst hilft es bestimmt mal rein zu schauen.
gruss
andre
Ich kenne das Modul danke. John hat es auch hier schon auf der ersten Seite erwähnt. Aber ich will mit diesem Modul lernen wie man ein Modul schreibt ;) Hatte es vorher schon so in php programmiert (anderes Haussteuerungsystem) und perl sagt mir bisher sehr sehr wenig.
Deshalb strapazier ich hier deine nerven so ;)
Grüße
du musst InternalTimer für run aufrufen. nur für berechne.
gruss
andre
Hallo!
Zitat von: justme1968 am 30 Dezember 2013, 10:35:55
du musst InternalTimer für run aufrufen. nur für berechne.
Sry ich versteh nicht was du meinst.
Ich hab jetzt das Aufrufen der Berechnung in der Run auskommentiert und einen zweiten Timer in der cc_berechnen() gesetzt, der wenn $hash->{running} > 0 ist, cc_berechnen() alle x Sekunden wieder startet. Das klappt.
Wenn ich dann aber das Device off schalte werden die readings richtig gesetzt, aber nach ca. 30 Sekunden wird die cc_berechnen() nochmals aufgerufen, obwohl $hash->{running} schon 0 ist.
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday sleep);
sub currentCalculator_Initialize($) {
my ($hash) = @_;
$hash->{GetFn} = "currentCalculator_Get";
$hash->{SetFn} = "currentCalculator_Set";
$hash->{DefFn} = "currentCalculator_Define";
$hash->{UndefFn} = "currentCalculator_Undefine";
$hash->{NotifyFn} = "currentCalculator_NotifyFn";
}
#####################################
sub currentCalculator_Define($$) {
my ( $hash, $def ) = @_;
my $version = "0.1";
my @a = split( "[ \t][ \t]*", $def );
return "Usage: define <name> currentCalculator [device] [watt] [invterval]"
if ( @a < 4 || @a > 5 );
my $name = $a[0];
my $device = $a[2];
my $watt = $a[3];
my $interval = 60;
$interval = $a[4] if ( $interval < 60 );
$hash->{NAME} = $name;
$hash->{DEVICE} = $device;
$hash->{STATE} = "Active";
$hash->{INTERVAL} = $interval;
$hash->{WATT} = $watt;
Log3 $name, 3, "[currentCalculator v".$version." initialisiert]";
return undef;
}
sub currentCalculator_Set() {}
sub currentCalculator_Get() {}
sub currentCalculator_Undefine($) {
my ($hash) = @_;
RemoveInternalTimer($hash->{NAME});
return undef;
}
sub currentCalculator_NotifyFn($$) {
my ( $hash, $dev ) = @_;
return if($dev->{NAME} ne $hash->{DEVICE});
my $name = $hash->{NAME};
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
#----- Untoggle Fix-----#
if ( Value( $device ) eq "toggle" ) {
if ( OldValue( $device ) eq "off" ) {
fhem("set $device on");
}
else {
fhem("set $device off");
}
}
my $on = "";
if( Value($device) eq "on") {
if( $hash->{running} <= 0)
{
$hash->{running} = 1;
currentCalculator_Run($hash);
}
}
elsif ( Value($device) eq "off" ) {
if( $hash->{running} > 0)
{
$hash->{running} = 0;
my $on = ReadingsVal( $device, "on", "0" );
my $off = int( time() );
my $onLast = $off - $on;
currentCalculator_setReading( $device, "off", $off );
currentCalculator_Berechnen( $hash, $device, $watt );
currentCalculator_setReading( $device, "on", 0 );
currentCalculator_setReading( $device, "onNow", 0 );
currentCalculator_setReading( $device, "power", 0 );
currentCalculator_setReading( $device, "onLast", $onLast );
RemoveInternalTimer($hash->{NAME});
}
}
else {
Log3 $name, 3, "[currentCalculator] Kein on/off state";
}
return undef;
}
#----- Stromverbrauch Startzeit setzen -----#
sub currentCalculator_Run($){
my ($hash) = @_;
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
my $on = int( time() );
currentCalculator_setReading( $device, "on", $on );
currentCalculator_setReading( $device, "power", $watt );
#currentCalculator_Berechnen($hash,$device,$watt);
RemoveInternalTimer($hash->{NAME});
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "currentCalculator_Berechnen",$hash, 0);
Log3 $device, 3, "[currentCalculator] cc_Run";
}
#----- Stromverbrauch berechnen -----#
sub currentCalculator_Berechnen($$$) {
my ($hash) = @_;
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
my $on = "";
my $off = 0;
my $onNow = 0;
my $consumptionLast = 0;
my $onTotal = 0;
my $consumptionTotal = 0;
Log3 $device, 3, "[currentCalculator] cc_Berechnen";
$on = ReadingsVal( $device, "on", "0" );
$off = int( time() );
$onNow = $off - $on;
$onTotal = ReadingsVal( $device, "onTotal", "0" );
$consumptionTotal = ReadingsVal( $device, "consumptionTotal", "0" );
$onTotal = int( $onTotal + $onNow );
$consumptionLast = $onNow * $watt / 1000 / 3600;
$consumptionTotal = $consumptionTotal + $consumptionLast;
$consumptionTotal = sprintf "%.2f", $consumptionTotal;
currentCalculator_setReading( $device, "on", $on );
currentCalculator_setReading( $device, "onNow", $onNow );
currentCalculator_setReading( $device, "onTotal", $onTotal );
currentCalculator_setReading( $device, "consumptionTotal", $consumptionTotal );
if( $hash->{running} > 0 ) {
RemoveInternalTimer($hash->{NAME});
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "currentCalculator_Berechnen",$hash, 0);
}
}
#----- setReading -----#
sub currentCalculator_setReading($$$) {
my $device = shift;
my $readingsName = shift;
my $readingsWert = shift;
Log3 $device, 3, "[currentCalculator] cc_setReading";
readingsBeginUpdate($main::defs{$device});
readingsBulkUpdate( $main::defs{$device}, $readingsName, $readingsWert );
readingsEndUpdate( $main::defs{$device}, 1 );
}
1;
Log on:
2013.12.30 11:15:21.793 3: FS20 set wzDeckenfluter on
2013.12.30 11:15:21.994 3: [currentCalculator] cc_setReading
2013.12.30 11:15:21.997 3: [currentCalculator] cc_setReading
2013.12.30 11:15:22.001 3: [currentCalculator] cc_Run
2013.12.30 11:15:37.255 3: FS20 set wzDeckenfluter off
2013.12.30 11:15:37.502 3: [currentCalculator] cc_setReading
2013.12.30 11:15:37.505 3: [currentCalculator] cc_Berechnen
2013.12.30 11:15:37.507 3: [currentCalculator] cc_setReading
2013.12.30 11:15:37.511 3: [currentCalculator] cc_setReading
2013.12.30 11:15:37.514 3: [currentCalculator] cc_setReading
2013.12.30 11:15:37.518 3: [currentCalculator] cc_setReading
2013.12.30 11:15:37.521 3: [currentCalculator] cc_setReading
2013.12.30 11:15:37.524 3: [currentCalculator] cc_setReading
2013.12.30 11:15:37.526 3: [currentCalculator] cc_setReading
2013.12.30 11:15:37.529 3: [currentCalculator] cc_setReading
2013.12.30 11:16:22.005 3: [currentCalculator] cc_Berechnen
2013.12.30 11:16:22.006 3: [currentCalculator] cc_setReading
2013.12.30 11:16:22.259 3: [currentCalculator] cc_setReading
2013.12.30 11:16:22.528 3: [currentCalculator] cc_setReading
2013.12.30 11:16:22.788 3: [currentCalculator] cc_setReading
2013.12.30 11:18:49.686 3: FS20 set wzDeckenfluter on
2013.12.30 11:18:49.920 3: [currentCalculator] cc_setReading
2013.12.30 11:18:49.923 3: [currentCalculator] cc_setReading
2013.12.30 11:18:49.928 3: [currentCalculator] cc_Run
2013.12.30 11:18:57.067 3: FHT8V set szStellventil valve 7
2013.12.30 11:19:49.932 3: [currentCalculator] cc_Berechnen
2013.12.30 11:19:49.934 3: [currentCalculator] cc_setReading
2013.12.30 11:19:50.226 3: [currentCalculator] cc_setReading
2013.12.30 11:19:50.514 3: [currentCalculator] cc_setReading
2013.12.30 11:19:50.758 3: [currentCalculator] cc_setReading
2013.12.30 11:20:51.013 3: [currentCalculator] cc_Berechnen
2013.12.30 11:20:51.015 3: [currentCalculator] cc_setReading
2013.12.30 11:20:51.321 3: [currentCalculator] cc_setReading
2013.12.30 11:20:51.562 3: [currentCalculator] cc_setReading
2013.12.30 11:20:51.806 3: [currentCalculator] cc_setReading
2013.12.30 11:21:52.053 3: [currentCalculator] cc_Berechnen
2013.12.30 11:21:52.055 3: [currentCalculator] cc_setReading
2013.12.30 11:21:52.344 3: [currentCalculator] cc_setReading
2013.12.30 11:21:52.643 3: [currentCalculator] cc_setReading
2013.12.30 11:21:52.886 3: [currentCalculator] cc_setReading
2013.12.30 11:22:53.140 3: [currentCalculator] cc_Berechnen
2013.12.30 11:22:53.142 3: [currentCalculator] cc_setReading
2013.12.30 11:22:53.435 3: [currentCalculator] cc_setReading
2013.12.30 11:22:53.710 3: [currentCalculator] cc_setReading
2013.12.30 11:22:53.949 3: [currentCalculator] cc_setReading
Log off:
2013.12.30 11:27:26.320 3: FS20 set wzDeckenfluter off
2013.12.30 11:27:26.536 3: [currentCalculator] cc_setReading
2013.12.30 11:27:26.539 3: [currentCalculator] cc_Berechnen
2013.12.30 11:27:26.541 3: [currentCalculator] cc_setReading
2013.12.30 11:27:26.544 3: [currentCalculator] cc_setReading
2013.12.30 11:27:26.546 3: [currentCalculator] cc_setReading
2013.12.30 11:27:26.549 3: [currentCalculator] cc_setReading
2013.12.30 11:27:26.552 3: [currentCalculator] cc_setReading
2013.12.30 11:27:26.555 3: [currentCalculator] cc_setReading
2013.12.30 11:27:26.558 3: [currentCalculator] cc_setReading
2013.12.30 11:27:26.560 3: [currentCalculator] cc_setReading
2013.12.30 11:28:09.129 3: [currentCalculator] cc_Berechnen
2013.12.30 11:28:09.131 3: [currentCalculator] cc_setReading
2013.12.30 11:28:09.432 3: [currentCalculator] cc_setReading
2013.12.30 11:28:09.722 3: [currentCalculator] cc_setReading
2013.12.30 11:28:09.978 3: [currentCalculator] cc_setReading
Hast du noch Idee?
Grüße
du brauchst nur einen timer. aber die funktion die du per timer aufrufst muss den timer immer wieder starten weil der timer sonst nur ein mal aufgerufen wird.
die logik sollte etwa so sein:
- wenn du im notify bemerkst das dein device ein geschaltet wurde rufst du ein mal run auf
- in run rufts du deine berechnung auf und startest mit RemoveInternalTimer / InternalTimer dein timer immer wieder neu. aber für run. nicht für berechne so wie in der vorherigen version.
das ist deine schleife die jede minute aufgerufen wird ohne das du etwas tun musst - wenn du im notify feststellst das dein device aus geschaltet wurde entfernst du den timer und rufst ein mal die berechnung für die angebrochene minute auf
gruss
andre
Ich verstehs nicht... ich denke ich hab alle deine punkte eingebaut aber das off klappt immer noch nicht.
Das run() wird auch aufgerufen wenn das device off ist. Aber warum? Das ist doch eine if davor die checkt ob $hash->{DEVICE} off ist.
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday sleep);
sub currentCalculator_Initialize($) {
my ($hash) = @_;
$hash->{GetFn} = "currentCalculator_Get";
$hash->{SetFn} = "currentCalculator_Set";
$hash->{DefFn} = "currentCalculator_Define";
$hash->{UndefFn} = "currentCalculator_Undefine";
$hash->{NotifyFn} = "currentCalculator_NotifyFn";
}
#####################################
sub currentCalculator_Define($$) {
my ( $hash, $def ) = @_;
my $version = "0.1";
my @a = split( "[ \t][ \t]*", $def );
return "Usage: define <name> currentCalculator [device] [watt] [invterval]"
if ( @a < 4 || @a > 5 );
my $name = $a[0];
my $device = $a[2];
my $watt = $a[3];
my $interval = 60;
$interval = $a[4] if ( $interval < 60 );
$hash->{NAME} = $name;
$hash->{DEVICE} = $device;
$hash->{STATE} = "Active";
$hash->{INTERVAL} = $interval;
$hash->{WATT} = $watt;
Log3 $name, 3, "[currentCalculator v".$version." initialisiert]";
return undef;
}
sub currentCalculator_Set() {}
sub currentCalculator_Get() {}
sub currentCalculator_Undefine($) {
my ($hash) = @_;
RemoveInternalTimer($hash->{NAME});
return undef;
}
sub currentCalculator_NotifyFn($$) {
my ( $hash, $dev ) = @_;
return if($dev->{NAME} ne $hash->{DEVICE});
my $name = $hash->{NAME};
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
#----- Untoggle Fix-----#
if ( Value( $device ) eq "toggle" ) {
if ( OldValue( $device ) eq "off" ) {
fhem("set $device on");
}
else {
fhem("set $device off");
}
}
my $on = "";
if( Value($device) eq "on") {
if( $hash->{running} == 0)
{
currentCalculator_Run($hash);
}
}
elsif( Value($device) eq "off" ) {
if( $hash->{running} == 1)
{
$hash->{running} = 0;
RemoveInternalTimer($hash->{NAME});
my $on = ReadingsVal( $device, "on", "0" );
my $off = int( time() );
my $onLast = $off - $on;
currentCalculator_setReading( $device, "off", $off );
currentCalculator_Berechnen( $hash, $device, $watt );
currentCalculator_setReading( $device, "on", 0 );
currentCalculator_setReading( $device, "onNow", 0 );
currentCalculator_setReading( $device, "power", 0 );
currentCalculator_setReading( $device, "onLast", $onLast );
}
}
else {
Log3 $name, 3, "[currentCalculator] Kein on/off state";
}
return undef;
}
#----- Stromverbrauch Run setzen -----#
sub currentCalculator_Run($){
my ($hash) = @_;
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
Log3 $device, 3, "[currentCalculator] cc_Run";
if( $hash->{running} <= 0 )
{
$hash->{running} = 1;
my $on = int( time() );
currentCalculator_setReading( $device, "on", $on );
currentCalculator_setReading( $device, "power", $watt );
}
currentCalculator_Berechnen($hash,$device,$watt);
RemoveInternalTimer($hash->{NAME});
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "currentCalculator_Run",$hash, 0);
}
#----- Stromverbrauch berechnen -----#
sub currentCalculator_Berechnen($$$) {
my ($hash) = @_;
my $device = $hash->{DEVICE};
my $watt = $hash->{WATT};
my $on = "";
my $now = 0;
my $onNow = 0;
my $consumptionLast = 0;
my $onTotal = 0;
my $consumptionTotal = 0;
Log3 $device, 3, "[currentCalculator] cc_Berechnen";
$on = ReadingsVal( $device, "on", "0" );
$now = int( time() );
$onNow = $now - $on;
$onTotal = ReadingsVal( $device, "onTotal", "0" );
$consumptionTotal = ReadingsVal( $device, "consumptionTotal", "0" );
$onTotal = int( $onTotal + $onNow );
$consumptionLast = $onNow * $watt / 1000 / 3600;
$consumptionTotal = $consumptionTotal + $consumptionLast;
$consumptionTotal = sprintf "%.2f", $consumptionTotal;
currentCalculator_setReading( $device, "on", $on );
currentCalculator_setReading( $device, "onNow", $onNow );
currentCalculator_setReading( $device, "onTotal", $onTotal );
currentCalculator_setReading( $device, "consumptionTotal", $consumptionTotal );
}
#----- setReading -----#
sub currentCalculator_setReading($$$) {
my $device = shift;
my $readingsName = shift;
my $readingsWert = shift;
Log3 $device, 3, "[currentCalculator] cc_setReading";
readingsBeginUpdate($main::defs{$device});
readingsBulkUpdate( $main::defs{$device}, $readingsName, $readingsWert );
readingsEndUpdate( $main::defs{$device}, 1 );
}
1;
Log:
2013.12.30 12:16:11.645 3: FS20 set wzDeckenfluter off
2013.12.30 12:16:11.855 3: [currentCalculator] cc_setReading
2013.12.30 12:16:11.858 3: [currentCalculator] cc_Berechnen
2013.12.30 12:16:11.860 3: [currentCalculator] cc_setReading
2013.12.30 12:16:11.863 3: [currentCalculator] cc_setReading
2013.12.30 12:16:11.866 3: [currentCalculator] cc_setReading
2013.12.30 12:16:11.869 3: [currentCalculator] cc_setReading
2013.12.30 12:16:11.872 3: [currentCalculator] cc_setReading
2013.12.30 12:16:11.874 3: [currentCalculator] cc_setReading
2013.12.30 12:16:11.877 3: [currentCalculator] cc_setReading
2013.12.30 12:16:11.880 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.013 3: [currentCalculator] cc_Run
2013.12.30 12:17:05.014 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.260 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.263 3: [currentCalculator] cc_Berechnen
2013.12.30 12:17:05.265 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.268 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.272 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.275 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.279 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.282 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.285 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.289 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.348 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.620 3: [currentCalculator] cc_Berechnen
2013.12.30 12:17:05.622 3: [currentCalculator] cc_setReading
2013.12.30 12:17:05.875 3: [currentCalculator] cc_setReading
2013.12.30 12:17:06.130 3: [currentCalculator] cc_setReading
2013.12.30 12:17:06.392 3: [currentCalculator] cc_setReading
Grüße
Ich habs :D
Das viele copy & paste war schuld. Ich hab den timer mit InternalTimer(gettimeofday()+$hash->{INTERVAL}, "currentCalculator_Run",$hash, 0); gesetzt, aber mit RemoveInternalTimer($hash->{NAME}); entfernt. Nachdem ich das auf $hash abgeändert hab funktioniert's :D
Vielen vielen Dank für deine Hilfe und Geduld, alleine hätte ich das nie geschafft :)
Hättest du noch ein paar Tipps was am code selbst verbessern könnte? Oder passt das im großen und ganzen so?
z.B das readings setzen, da gibts ja noch andere Lösungen hab ich gesehen. Im pid Modul wird zB das reading mit $pid->{READINGS}{$name}{VAL} = $val; gesetzt. Ich mach das ganz anders, wie hier (http://forum.fhem.de/index.php/topic,13270.msg83082.html#msg83082) von MisterEltako beschrieben.
Grüße
du solltest auf jeden fall die readings update funktionen verwenden. das sind die einzigen bei denen die event-on-change & Co gehen, bei denen user readings und notifys gehen. alles andere ist veraltet oder blödsinn :)
es gibt ein paar stellen die noch aufgeräumt werden können. du brauchst z.b. nichts an eine funktion zu übergeben das auch im
hash steckt. das erkenne von ein und aus könnte man verbessern. usw. aber da kommst du sicher voneinander drauf mit der zeit wenn du drüber nachdenkst :)
gruss
andre