diff --git a/fhem/FHEM/70_JSONMETER.pm b/fhem/FHEM/70_JSONMETER.pm index a5e682462..8f82f3b8a 100644 --- a/fhem/FHEM/70_JSONMETER.pm +++ b/fhem/FHEM/70_JSONMETER.pm @@ -55,9 +55,12 @@ sub JSONMETER_ReadFromUrl($); sub JSONMETER_ReadFromFile($); sub JSONMETER_ParseJsonFile($); sub JSONMETER_UpdateAborted($); +sub JSONMETER_doStatisticMinMax ($$$); +sub JSONMETER_doStatisticMinMaxSingle ($$$$); +sub JSONMETER_doStatisticDelta ($$$); # Modul Version for remote debugging - my $modulVersion = "2014-02-20"; + my $modulVersion = "2014-03-03"; ############################################################## # Syntax: meterType => port URL-Path @@ -91,16 +94,16 @@ sub JSONMETER_UpdateAborted($); ,[1, "1.8.3|0101010803FF", "electricityConsumedTariff3", 2] # {"obis":"0101010803FF","value":33.53,"unit":"kWh"}, ,[1, "1.8.4|0101010804FF", "electricityConsumedTariff4", 2] # {"obis":"0101010804FF","value":33.53,"unit":"kWh"}, ,[1, "1.8.5|0101010805FF", "electricityConsumedTariff5", 2] # {"obis":"0101010805FF","value":33.53,"unit":"kWh"}, - ,[1, "010001080080", "electricityConsumedToday", 1] - ,[1, "010001080081", "electricityConsumedYesterday", 1] - ,[1, "010001080082", "electricityConsumedLastWeek", 1] - ,[1, "010001080083", "electricityConsumedLastMonth", 1] - ,[1, "010001080084", "electricityConsumedLastYear", 1] - ,[1, "010002080080", "electricityProducedToday", 1] - ,[1, "010002080081", "electricityProducedYesterday", 1] - ,[1, "010002080082", "electricityProducedLastWeek", 1] - ,[1, "010002080083", "electricityProducedLastMonth", 1] - ,[1, "010002080084", "electricityProducedLastYear", 1] + ,[1, "010001080080", "electricityConsumedToday", 0] + ,[1, "010001080081", "electricityConsumedYesterday", 0] + ,[1, "010001080082", "electricityConsumedLastWeek", 0] + ,[1, "010001080083", "electricityConsumedLastMonth", 0] + ,[1, "010001080084", "electricityConsumedLastYear", 0] + ,[1, "010002080080", "electricityProducedToday", 0] + ,[1, "010002080081", "electricityProducedYesterday", 0] + ,[1, "010002080082", "electricityProducedLastWeek", 0] + ,[1, "010002080083", "electricityProducedLastMonth", 0] + ,[1, "010002080084", "electricityProducedLastYear", 0] ,[1, "0101020800FF", "electricityPowerOutput", 1] ,[1, "010020070000", "electricityVoltagePhase1", 1] #{"obis":"010020070000","value":237.06,"unit":"V"}, ,[1, "010034070000", "electricityVoltagePhase2", 1] # {"obis":"010034070000","value":236.28,"unit":"V"}, @@ -230,29 +233,40 @@ JSONMETER_Set($$@) { my ($hash, $name, $cmd, $val) = @_; my $resultStr = ""; - + if($cmd eq 'statusRequest') { $hash->{LOCAL} = 1; JSONMETER_GetUpdate($hash); $hash->{LOCAL} = 0; return undef; } - elsif($cmd eq 'restartJsonAnalysis') { - $hash->{fhem}{jsonInterpreter} = ""; - $hash->{LOCAL} = 1; - JSONMETER_GetUpdate($hash); - $hash->{LOCAL} = 0; - return undef; - } - elsif($cmd eq 'INTERVAL' && int(@_)==4 ) { - $val = 10 if( $val < 10 ); - $hash->{INTERVAL}=$val; - return "$name: Polling interval set to $val seconds."; - } - my $list = "statusRequest:noArg" + elsif($cmd eq 'restartJsonAnalysis') { + $hash->{fhem}{jsonInterpreter} = ""; + $hash->{LOCAL} = 1; + JSONMETER_GetUpdate($hash); + $hash->{LOCAL} = 0; + return undef; + } + elsif ($cmd eq 'resetStatistics') { + foreach (sort keys %{ $hash->{READINGS} }) { + if ($_ =~ /^\.?stat/ && $_ ne "state") { + delete $hash->{READINGS}{$_}; + $resultStr .= "$name: Reading '$_' deleted\n"; + } + } + WriteStatefile(); + return $resultStr; + } + elsif($cmd eq 'INTERVAL' && int(@_)==4 ) { + $val = 10 if( $val < 10 ); + $hash->{INTERVAL}=$val; + return "$name: Polling interval set to $val seconds."; + } + my $list = "statusRequest:noArg" + ." resetStatistics:noArg" ." restartJsonAnalysis:noArg" ." INTERVAL:slider,0,10,600"; - return "Unknown argument $cmd, choose one of $list"; + return "Unknown argument $cmd, choose one of $list"; } # end JSONMETER_Set @@ -434,6 +448,7 @@ JSONMETER_ParseJsonFile($) my $name = $hash->{NAME}; my $value; my $returnStr; + my $statisticType; delete($hash->{helper}{RUNNING_PID}); @@ -514,6 +529,7 @@ if ( $a[1] == 1 ){ my @a = split /\|/, $jsonInterpreter; Log3 $name, 4, "$name: Extract ".($#a+1)." readings from ".($#fields+1)." json parts"; foreach (@a) { + $statisticType = 0; Log3 $name, 5, "$name: Handle $_"; my @b = split / /, $_ ; if ($b[1] == 1) { #obis value @@ -522,7 +538,8 @@ if ( $a[1] == 1 ){ # $value =~ s/^\s+|\s+$//g; Log3 $name, 4, "$name: Value $value for reading $b[2] extracted from '$fields[$b[0]]'"; $returnStr .= "Value \"$value\" for reading '$b[2]' extracted from part $b[0]:\n$fields[$b[0]]\n\n"; - readingsBulkUpdate($hash,$b[2],$value); + readingsBulkUpdate($hash,$b[2],$value); + $statisticType = $b[3]; } else { Log3 $name, 4, "$name: Could not extract value for reading $b[2] from '$fields[$b[0]]'"; $returnStr .= "Could not extract value for reading '$b[2]' from part $b[0]:\n$fields[$b[0]]\n\n"; @@ -533,6 +550,7 @@ if ( $a[1] == 1 ){ Log3 $name, 4, "$name: Value $value for reading $b[2] extracted from '$fields[$b[0]]'"; $returnStr .= "Value \"$value\" for reading '$b[2]' extracted from part $b[0]:\n$fields[$b[0]]\n\n"; readingsBulkUpdate($hash,$b[2],$value); + $statisticType = $b[3]; } else { Log3 $name, 4, "$name: Could not extract value for reading $b[2] from '$fields[$b[0]]'"; $returnStr .= "Could not extract value for reading '$b[2]' from part $b[0]:\n$fields[$b[0]]\n\n"; @@ -544,6 +562,7 @@ if ( $a[1] == 1 ){ Log3 $name, 4, "$name: Value $value for reading $b[2] extracted from '$fields[$b[0]]'"; $returnStr .= "Value \"$value\" for reading '$b[2]' extracted from part $b[0]:\n$fields[$b[0]]\n\n"; readingsBulkUpdate($hash, $b[2], $value); + $statisticType = $b[3]; } else { Log3 $name, 4, "$name: Could not extract value for reading $b[2] from '$fields[$b[0]]'"; $returnStr .= "Could not extract value for reading '$b[2]' from part $b[0]:\n$fields[$b[0]]\n\n"; @@ -555,14 +574,22 @@ if ( $a[1] == 1 ){ $returnStr .= "Value \"$value\" for reading '$b[2]' extracted from part $b[0]:\n$fields[$b[0]]\n\n"; $value = strftime "%Y-%m-%d %H:%M:%S", localtime($value); readingsBulkUpdate($hash, $b[2], $value); + $statisticType = $b[3]; } else { Log3 $name, 4, "$name: Could not extract value for reading $b[2] from '$fields[$b[0]]'"; $returnStr .= "Could not extract value for reading '$b[2]' from part $b[0]:\n$fields[$b[0]]\n\n"; } } - } + + if ( AttrVal($name,"doStatistics",0) == 1) { + # JSONMETER_doStatisticMinMax $hash, $readingName, $value + if ($statisticType == 1 ) { JSONMETER_doStatisticMinMax $hash, "stat".ucfirst($b[2]), $value ; } + # JSONMETER_doStatisticDelta: $hash, $readingName, $value + if ($statisticType == 2 ) { JSONMETER_doStatisticDelta $hash, "stat".ucfirst($b[2]), $value ; } + } + } - readingsBulkUpdate($hash,"state","Connected"); + readingsBulkUpdate($hash,"state","Connected"); readingsEndUpdate($hash,1); DoTrigger($hash->{NAME}, undef) if ($init_done); @@ -584,6 +611,204 @@ JSONMETER_UpdateAborted($) } # end JSONMETER_UpdateAborted +# Calculates single MaxMin Values and informs about end of day and month +sub ######################################## +JSONMETER_doStatisticMinMax ($$$) +{ + my ($hash, $readingName, $value) = @_; + my $dummy; + + my $lastReading; + my $lastSums; + my @newReading; + + my $yearLast; + my $monthLast; + my $dayLast; + my $dayNow; + my $monthNow; + my $yearNow; + + # Determine date of last and current reading + if (exists($hash->{READINGS}{$readingName."Day"}{TIME})) { + ($yearLast, $monthLast, $dayLast) = $hash->{READINGS}{$readingName."Day"}{TIME} =~ /^(\d\d\d\d)-(\d\d)-(\d\d)/; + } else { + ($dummy, $dummy, $dummy, $dayLast, $monthLast, $yearLast) = localtime; + $yearLast += 1900; + $monthLast ++; + } + ($dummy, $dummy, $dummy, $dayNow, $monthNow, $yearNow) = localtime; + $yearNow += 1900; + $monthNow ++; + + # Daily Statistic + #JSONMETER_doStatisticMinMaxSingle: $hash, $readingName, $value, $saveLast + JSONMETER_doStatisticMinMaxSingle $hash, $readingName."Day", $value, ($dayNow != $dayLast); + + # Monthly Statistic + #JSONMETER_doStatisticMinMaxSingle: $hash, $readingName, $value, $saveLast + JSONMETER_doStatisticMinMaxSingle $hash, $readingName."Month", $value, ($monthNow != $monthLast); + + # Yearly Statistic + #JSONMETER_doStatisticMinMaxSingle: $hash, $readingName, $value, $saveLast + JSONMETER_doStatisticMinMaxSingle $hash, $readingName."Year", $value, ($yearNow != $yearLast); + + return ; + +} + +# Calculates single MaxMin Values and informs about end of day and month +sub ######################################## +JSONMETER_doStatisticMinMaxSingle ($$$$) +{ + my ($hash, $readingName, $value, $saveLast) = @_; + my $result; + + my $lastReading = $hash->{READINGS}{$readingName}{VAL} || ""; + + # Initializing + if ( $lastReading eq "" ) { + my $since = strftime "%Y-%m-%d_%H:%M:%S", localtime(); + $result = "Count: 1 Sum: $value ShowDate: 1"; + readingsBulkUpdate($hash, ".".$readingName, $result); + $result = "Min: $value Avg: $value Max: $value (since: $since )"; + readingsBulkUpdate($hash, $readingName, $result); + + # Calculations + } else { + my @a = split / /, $hash->{READINGS}{"." . $readingName}{VAL}; # Internal values + my @b = split / /, $lastReading; + # Do calculations + if ($saveLast) { + readingsBulkUpdate($hash, $readingName . "Last", $lastReading); + $a[1] = 1; $a[3] = $value; $a[5] = 0; + $b[1] = $value; $b[3] = $value; $b[5] = $value; + } else { + $a[1]++; # Count + $a[3] += $value; # Sum + if ($value < $b[1]) { $b[1]=$value; } # Min + $b[3] = sprintf "%.0f" , $a[3] / $a[1]; # Avg + if ($value > $b[5]) { $b[5]=$value; } # Max + } + # Store internal calculation values + $result = "Count: $a[1] Sum: $a[3] ShowDate: $a[5]"; + readingsBulkUpdate($hash, ".".$readingName, $result); + # Store visible Reading + $result = "Min: $b[1] Avg: $b[3] Max: $b[5]"; + if ($a[5] == 1) { $result .= " (since: $b[7] )"; } + readingsBulkUpdate($hash, $readingName, $result); + } + return; +} + + +# Calculates deltas for day, month and year +sub ######################################## +JSONMETER_doStatisticDelta ($$$) +{ + my ($hash, $readingName, $value) = @_; + my $dummy; + + my @curr = split / /, $hash->{READINGS}{$readingName}{VAL} || ""; + my @start = split / /, $hash->{READINGS}{"." . $readingName . "Start"}{VAL} || ""; + + my $saveLast=0; + my @last; + if (exists ($hash->{READINGS}{$readingName."Last"})) { + @last = split / /, $hash->{READINGS}{$readingName."Last"}{VAL}; + } else { + @last = split / /, "Day: - Month: - Year: -"; + } + + my $result; + my $yearLast; + my $monthLast; + my $dayLast; + my $dayNow; + my $monthNow; + my $yearNow; + + # Determine date of last and current reading + if (exists($hash->{READINGS}{$readingName}{TIME})) { + ($yearLast, $monthLast, $dayLast) = ($hash->{READINGS}{$readingName}{TIME} =~ /^(\d\d\d\d)-(\d\d)-(\d\d)/); + } else { + ($dummy, $dummy, $dummy, $dayLast, $monthLast, $yearLast) = localtime; + $yearLast += 1900; + $monthLast ++; + $start[1] = $value; + $start[3] = $value; + $start[5] = $value; + $start[7] = 6; + $curr[7] = strftime "%Y-%m-%d_%H:%M:%S", localtime(); # Start + } + ($dummy, $dummy, $dummy, $dayNow, $monthNow, $yearNow) = localtime; + $yearNow += 1900; + $monthNow ++; + + # Yearly Statistic + if ($yearNow != $yearLast){ + $last[5] = $curr[5]; + $start[5] = $value; + # Do not show the "since:" value for year changes anymore + if ($start[7] == 1) { $start[7] = 0; } + # Shows the "since:" value for the first year change + if ($start[7] >= 2) { + $last[7] = $curr[7]; + $start[7] = 1; + } + } + $curr[5] = $value - $start[5]; + + # Monthly Statistic + if ($monthNow != $monthLast){ + $last[3] = $curr[3]; + $start[3] = $value; + # Do not show the "since:" value for month changes anymore + if ($start[7] == 3) { $start[7] = 2; } + # Shows the "since:" value for the first month change + if ($start[7] >= 4) { + $last[7] = $curr[7]; + $start[7] = 3; + } + } + $curr[3] = $value - $start[3]; + + # Daily Statistic + if ($dayNow != $dayLast){ + $last[1] = $curr[1]; + $start[1] = $value; + # Do not show the "since:" value for day changes anymore + if ($start[7] == 5) { $start[7] = 4; } + # Shows the "since:" value for the first day change + if ($start[7] >= 6) { + $last[7] = $curr[7]; + $start[7] = 5; + # Next monthly and yearly values start at 00:00 + $curr[7] = strftime "%Y-%m-%d", localtime(); # Start + $start[3] = $value; + $start[5] = $value; + } + $saveLast = 1; + } + $curr[1] = $value - $start[1]; + + # Store internal calculation values + $result = "Day: $start[1] Month: $start[3] Year: $start[5] ShowDate: $start[7]"; + readingsBulkUpdate($hash, ".".$readingName."Start", $result); + + # Store visible Reading + $result = "Day: $curr[1] Month: $curr[3] Year: $curr[5]"; + if ($start[7] != 0 ) { $result .= " (since: $curr[7] )"; } + readingsBulkUpdate($hash,$readingName,$result); + + if ($saveLast == 1) { + $result = "Day: $last[1] Month: $last[3] Year: $last[5]"; + if ( $start[7] =~ /1|3|5/ ) { $result .= " (since: $last[7] )";} + readingsBulkUpdate($hash,$readingName."Last",$result); + } + + return ; +} 1; @@ -672,7 +897,9 @@ JSONMETER_UpdateAborted($)
  • doStatistics < 0 | 1 >
    - Calculates statistic values - not implemented yet + Calculate statistic values according to reading type (e.g. Average/Min/Max) +
    + Builds daily, monthly and yearly statistics of certain readings. For diagrams, log readings of type 'statReadingNameLast'.

  • pathString <string>