Script in Modul "umwandeln"

Begonnen von fhainz, 14 Dezember 2013, 12:43:23

Vorheriges Thema - Nächstes Thema

fhainz

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

justme1968

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
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

fhainz

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

justme1968

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.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

fhainz

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

justme1968

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
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

fhainz

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

justme1968

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
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

fhainz

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

justme1968

du musst InternalTimer für run aufrufen. nur für berechne.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

fhainz

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

justme1968

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
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

fhainz

#42
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

fhainz

#43
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 von MisterEltako beschrieben.


Grüße

justme1968

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
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968