Hallo Zusammen, Hallo liebe Energiedaten-Sammler,
nachdem es hier bereits auch schonmal diskutiert wurde und ich mich parallel versucht habe, bei github und iobroker schlauer zu machen, habe ich jetzt eine erste Lösung, wie man die Recordings auswerten kann.
Bei meinem ersten Versuch habe ich alle "Power" recordings ausgewertet. Entsprechende Links wurden hier ja auch schon mal gepostet. Ich bin mir aber nicht ganz sicher, ob die Daten bereits richtig ausgewertet werden. Buderus hat hier irgendwie eine seltsame Art, die Werte zu speichern. Das muß ich in den nächsten Tagen nochmal verifizieren oder es hat noch jemand eine Idee.
Für meine Tests habe ich das Modul 73_km200.pm leicht modifiziert. Das Problem war, dass die Services vom Typ "YRecording" bisher nicht ausgewertet wurden. Dies habe ich jetzt für die "Power"-Werte für den aktuellen Tag, den aktuellen Monat und das aktuelle Jahr umgesetzt. Der Service "/hs/actualPower" könnte man noch ausklammern.
Den nachfolgenden Code sollte man in die Funktion "km200_ParseHttpResponseInit($)" an der folgenden Stelle einbauen:
### Check whether the type is a systeminfo
elsif ($json -> {type} eq "systeminfo")
{
....
}
HIER DEN NACHFOLGENDEN CODE EINBAUEN
### Check whether the type is unknown
else
{
Diesen Code einbauen:
### Check whether the type is a recording and is a 'power' recording
elsif ($json -> {type} eq "yRecording" and ($json->{id} =~ /Power$/ or $json -> {interval} ne ""))
{
my $JsonId = $json->{id};
my $JsonType = $json->{type};
### Log entries for debugging purposes
Log3 $name, 5, $name. " : km200_ParseHttpResponseInit - value found for : " .$Service;
Log3 $name, 5, $name. " : km200_ParseHttpResponseInit - id : " .$JsonId;
Log3 $name, 5, $name. " : km200_ParseHttpResponseInit - type : " .$JsonType;
#check if it is parent of recording values and build the interval services
if($json -> {interval} eq "")
{
### Log file entry for debugging
Log3 $name, 4, $name . " : The following Service is parent for recordings : " .$JsonId;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
my @intervals = (sprintf ('%04d-%02d-%02d', $year+1900,$mon+1,$mday), sprintf ('%04d-%02d', $year+1900,$mon+1),sprintf ('%04d', $year+1900));
for(@intervals)
{
my $tmpid = $JsonId.'?interval='.$_;
### Log recording service for debugging
Log3 $name, 4, $name. " : km200_GetRecordings - add service: ". $tmpid;
### Add service to the list of all known services
push (@{$hash ->{Secret}{KM200ALLSERVICES}}, $tmpid);
}
### Sort the list of all services alphabetically
@{$hash ->{Secret}{KM200ALLSERVICES}} = sort @{$hash ->{Secret}{KM200ALLSERVICES}};
}
else
{
my $interval = $json->{interval};
my $sampleRate = $json->{sampleRate};
### Log recording values for debugging
Log3 $name, 4, $name. " : km200_ParseHttpResponseInit : ".$JsonId.':'.$interval.':'.$sampleRate;
my $energySum = 0;
foreach my $item (@{ $json->{recording} })
{
if($item->{c} ne 0)
{
if($sampleRate eq "P1H")
{
$energySum = $energySum + $item->{y} / $item->{c}
}
elsif($sampleRate eq "P1D")
{
$energySum = $energySum + $item->{y} / ($item->{c} / 24)
}
elsif($sampleRate eq "P31D")
{
### don't know which values für 'c' should be used
$energySum = $energySum + $item->{y} / ($item->{c} / 30 / 24)
}
}
}
### Create new Recording Result and write reading for fhem
my $intervalText = $sampleRate eq "P1H" ? "_Today_kWh" : $sampleRate eq "P1D" ? "_ThisMonth_kWh" : "_ThisYear_kWh";
my $TempJsonId = '/recordings'.$json->{recordedResource}{id}. $intervalText;
$energySum = sprintf('%.02f', $energySum);
readingsSingleUpdate( $hash, $TempJsonId, $energySum, 1);
### Log recording values for debugging
Log3 $name, 4, $name. " : km200_ParseHttpResponseInit energySum: ".$JsonId.':'.$energySum;
### Add service to the list of responding services
push (@KM200_RespondingServices, $Service);
}
### Log file entry for debugging
Log3 $name, 4, $name . " : The following Service can be read : " .$JsonId;
}
In der Funktion km200_ParseHttpResponseDyn wird nachfolgender Code quasi an der gleichen Stelle wie oben eingebaut:
### Check whether the type is a recording
elsif ($json -> {type} eq "yRecording" and ($json -> {interval} ne ""))
{
my $JsonId = $json->{id};
my $JsonType = $json->{type};
### Log entries for debugging purposes
Log3 $name, 5, $name. " : km200_ParseHttpResponseDyn - value found for : " .$Service;
Log3 $name, 5, $name. " : km200_ParseHttpResponseDyn - id : " .$JsonId;
Log3 $name, 5, $name. " : km200_ParseHttpResponseDyn - type : " .$JsonType;
my $interval = $json->{interval};
my $sampleRate = $json->{sampleRate};
### Log recording values for debugging
Log3 $name, 4, $name. " : km200_ParseHttpResponseDyn : ".$JsonId.':'.$interval.':'.$sampleRate;
my $energySum = 0;
foreach my $item (@{ $json->{recording} })
{
if($item->{c} ne 0)
{
if($sampleRate eq "P1H")
{
$energySum = $energySum + $item->{y} / $item->{c}
}
elsif($sampleRate eq "P1D")
{
$energySum = $energySum + $item->{y} / ($item->{c} / 24)
}
elsif($sampleRate eq "P31D")
{
### don't know which values für 'c' should be used
$energySum = $energySum + $item->{y} / ($item->{c} / 30 / 24)
}
}
}
### write reading for fhem
my $intervalText = $sampleRate eq "P1H" ? "_Today_kWh" : $sampleRate eq "P1D" ? "_ThisMonth_kWh" : "_ThisYear_kWh";
my $TempJsonId = '/recordings'.$json->{recordedResource}{id}. $intervalText;
$energySum = sprintf('%.02f', $energySum);
readingsSingleUpdate( $hash, $TempJsonId, $energySum, 1);
### Log recording values for debugging
Log3 $name, 4, $name. " : km200_ParseHttpRecordings energySum: ".$JsonId.':'.$energySum;
}
Da ich noch nicht allzu intensiv getestet habe, gibt es vielleicht noch ein paar Bugs. Profis können bestimmt auch noch besseren Code schreiben ;-).
In dem beigefügten Bild sieht man die Einträge aus meiner Device.
Ansonsten habe ich mal die gelesenen Werte beigefügt:
Für den Tag:
{"id":"/recordings/system/heatSources/hs1/actualPower?interval=2021-12-30","type":"yRecording","writeable":0,"recordable":0,"recordedResource":{"id":"/heatSources/actualPower","uri":"http://192.168.2.97/heatSources/actualPower"},"interval":"2021-12-30","sampleRate":"P1H","recording-type":"actual","recording":[{"y":115,"c":60},{"y":120,"c":60},{"y":120,"c":60},{"y":120,"c":60},{"y":118,"c":59},{"y":120,"c":60},{"y":120,"c":60},{"y":120,"c":60},{"y":175,"c":60},{"y":15,"c":60},{"y":108,"c":59},{"y":120,"c":60},{"y":120,"c":60},{"y":120,"c":60},{"y":65,"c":60},{"y":60,"c":60},{"y":5,"c":59},{"y":0,"c":60},{"y":55,"c":60},{"y":1,"c":0},{"y":1,"c":0},{"y":1,"c":0},{"y":1,"c":0},{"y":1,"c":0}]}
Für den Monat:
{"id":"/recordings/system/heatSources/hs1/actualPower?interval=2021-12","type":"yRecording","writeable":0,"recordable":0,"recordedResource":{"id":"/heatSources/actualPower","uri":"http://192.168.2.97/heatSources/actualPower"},"interval":"2021-12","sampleRate":"P1D","recording-type":"actual","recording":[{"y":4128,"c":1436},{"y":4782,"c":1436},{"y":5266,"c":1436},{"y":4912,"c":1436},{"y":4786,"c":1436},{"y":5027,"c":1436},{"y":4782,"c":1436},{"y":4607,"c":1436},{"y":3533,"c":928},{"y":1010,"c":422},{"y":1410,"c":355},{"y":228,"c":295},{"y":110,"c":160},{"y":3030,"c":1204},{"y":3537,"c":1436},{"y":3232,"c":1436},{"y":3524,"c":1436},{"y":4486,"c":1436},{"y":3707,"c":1436},{"y":4484,"c":1436},{"y":6450,"c":1436},{"y":8202,"c":1436},{"y":3795,"c":912},{"y":2372,"c":1065},{"y":1808,"c":668},{"y":2700,"c":958},{"y":1882,"c":804},{"y":2249,"c":949},{"y":3351,"c":1406},{"y":1796,"c":1137},{"y":0,"c":0}]}
Für das Jahr:
{"id":"/recordings/system/heatSources/hs1/actualPower?interval=2021","type":"yRecording","writeable":0,"recordable":0,"recordedResource":{"id":"/heatSources/actualPower","uri":"http://192.168.2.97/heatSources/actualPower"},"interval":"2021","sampleRate":"P31D","recording-type":"actual","recording":[{"y":144071,"c":39165},{"y":94399,"c":28754},{"y":89772,"c":38037},{"y":79773,"c":40221},{"y":37617,"c":29436},{"y":7477,"c":38356},{"y":9559,"c":40209},{"y":9144,"c":40209},{"y":10579,"c":40209},{"y":59168,"c":40205},{"y":82241,"c":28903},{"y":59098,"c":19582}]}
Hinweise und weitere Ideen nehme ich gerne auf.
Vielleicht wandert dieser Ansatz ja auch mal in das Originalmodul. Wäre schön, wenn die Werte tatsächlich richtig berechnet würden.
[UPDATE 31.12.2021]
Nachdem ich heute nochmal ein wenig getestet habe, ist mir natürlich direkt ein "dummer" Fehle aufgefallen. Bei der Initialisierung der Services bzw. der entsprechenden URL wird ja einmal das Datum ermittelt und eingetragen. Am nächsten Tag passt das Datum natürlich nicht mehr. Dafür habe ich jetzt noch eine kleine Funktion erstellt. Wahrscheinlich sollte man bei der Initialisierung einfach ein paar Platzhalter einbauen.
Die folgende Funktion prüft die URL und setzt ein neues Datum:
###START###### Subroutine check date of recording and change it for today #####################################START####
sub km200_CheckRecordingUrl($$)
{
my ($name, $url) = @_;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
my @intervals = (sprintf ('%04d-%02d-%02d', $year+1900,$mon+1,$mday), sprintf ('%04d-%02d', $year+1900,$mon+1),sprintf ('%04d', $year+1900));
my @tmpurl = split("[?]interval=", $url);
$url = $tmpurl[0];
if(length($tmpurl[1]) eq 10)
{
$url = $url.'?interval='.$intervals[0];
}
elsif(length($tmpurl[1]) eq 7)
{
$url = $url.'?interval='.$intervals[1];
}
elsif(length($tmpurl[1]) eq 4)
{
$url = $url.'?interval='.$intervals[2];
}
Log3 $name, 5, $name. " : km200_CheckRecordingUrl new Url=".$url;
return $url;
}
###END###### Subroutine check date of recording and change it for today #####################################END####
Der Aufruf dieser Funktion erfolgt in der Funktion km200_GetDynService($) an folgender Stelle:
my $url = "http://" . $km200_gateway_host . $Service;
### START - NEUE FUNKTION ZUR ÄNDERUNG DES DATUMS
if($url =~ m/\?interval/ )
{
### Log file entry for debugging
Log3 $name, 5, $name . " - km200_GetDynService - Change Recording Url : " . $Service;
$url = km200_CheckRecordingUrl($name, $url);
}
### ENDE - NEUE FUNKTION ZUR ÄNDERUNG DES DATUMS
my $param = {
url => $url,
timeout => $PollingTimeout,
hash => $hash,
method => "GET",
header => "agent: TeleHeater/2.2.3\r\nUser-Agent: TeleHeater/2.2.3\r\nAccept: application/json",
callback => \&km200_ParseHttpResponseDyn
};
Mal sehen, was mir sonst noch so an Fehlern auffällt ;-).