Wenn Du openHAB 4 verwendest, ist automatisch rrd4j als Persistence Service aktiv. Weiterhin werden alle angelegten ITems automatisch mit everyChange, everyMinute gesichert, wenn Du nicht selbst eingreifst.
rrd4j speichert die Daten in verschiedenen Stufen und rotiert die Daten automatisch. (rrd -> Round Robin Database) Die Messwerte werden (zwingend) mindestens einmal pro Minute geschrieben. Das genaue Default Verhalten von rrd4j ist hier beschrieben:
https://www.openhab.org/addons/persiste ... datasource und läuft auf folgendes hinaus:
1. für die letzte Stunde eine zeitliche Auflösung von 10 Sekunden
2. für die letzten 7 Tage eine zeitliche Auflösung von einer Minute
3. für die letzten 365 Tage eine zeitliche Auflösung von 15 Minuten
4. für die letzten 5 Jahre eine zeitliche Auflösung von einer Stunde
5. für die letzten 10 Jahre eine zeitliche Auflösung von einem Tag.
Die jeweils gröberen Stufen werden durch Kumulation der Daten der nächst feineren Stufe ermittelt.
Kommt also alle 10 Sekunden ein Messwert rein, so wird der jeweils gespeichert. einmal pro Minute werden die Messwerte der letzten 60 Sekunden gemittelt (alle Werte addiert und durch die Anzahl der Werte geteilt), der neue Messwert wird in der zweiten Ebene Gespeichert.
alle 15 Minuten werden die letzten 15 Werte der Minutentabelle gemittelt und das Ergebnis wird in der dritten Ebene gespeichert.
Einmal pro Stunde werden die vier letzten Werte der Viertelstunden-Tabelle gemittelt und in der vierten Stufe gespeichert.
einmal täglich werden die letzten 24 Stundenwerte gemittelt und in der fünften Ebene gespeichert.
Auf diese Weise hält die Datenbank Messwerte der letzten 10 Jahre, wobei mit dem zeitlichen Abstand die Auflösung immer geringer wird.
Vorteil: Die Datenbank wächst nicht. die jeweils ältesten Werte pro Zeitabschnitt werden einfach überschrieben.
Für Graphen, deren aktuelles Ende auf "jetzt" zeigt, ist dieses Verhalten ideal, denn es können ohnehin nur eine begrenzte Anzahl Messpunkte gezeichnet werden. Wenn Du allerdings kurze Zeitabschnitte aus der ferneren Vergangenheit laden möchtest (z.B. um die Produktionswerte im Juni über die letzten Jahre miteinander zu vergleichen), dann stößt diese Form der Datenablage an ihre Grenzen.
Wenn Du also Wert auf genauere Daten legst, wirst Du nicht um eine andere Datenbank herum kommen.
Ich nutze ein php Script, um täglich alle Daten aus dem internen Speicher auszulesen und in eine MariaDB zu überführen.
Create Code:
Code: Alles auswählen
CREATE TABLE `tblData` (
`ID` INT(11) NOT NULL AUTO_INCREMENT,
`datum` DATETIME NOT NULL,
`key` MEDIUMINT(9) NOT NULL,
`tsis` INT(11) NOT NULL,
`cp1` FLOAT NOT NULL,
`cp2` FLOAT NOT NULL,
`cp3` FLOAT NOT NULL,
`cs1` FLOAT NOT NULL,
`cs2` FLOAT NOT NULL,
`erwsp` FLOAT NOT NULL,
`prps` FLOAT NOT NULL,
`tp` INT(11) NOT NULL,
`vp1` FLOAT NOT NULL,
`vp2` FLOAT NOT NULL,
`vp3` FLOAT NOT NULL,
`vs1` FLOAT NOT NULL,
`vs2` FLOAT NOT NULL,
PRIMARY KEY (`ID`) USING BTREE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=837699
;
PHP Script:
Code: Alles auswählen
<?php
$aktdat=new DateTime();
date_sub($aktdat,new DateInterval('P1D'));
$readdate= $aktdat->format('Y-m-d');
if($argc > 1){
$readdate=$argv[1];
}
$readdatee=$readdate;
if($argc > 2){
$readdatee=$argv[2];
}
// $readdate='2023-10-26';
// $readdatee='2023-10-28';
echo "\nVerwendetes Datum ", $readdate, " - ", $readdatee, " . ... Fordere Daten an.\n";
//die("\n\n Test \n\n");
//connect to mysql db
$con = mysqli_connect('<host>',<'pv-database>','<user>','<password>') or die('Could not connect: ' . mysql_error());
//read the json file contents
$url1='http://<ip.der.fronius.anlage>/solar_api/v1/GetArchiveData.cgi?Scope=System&SeriesType=Detail&HumanReadable=True&StartDate=';
$url2='&EndDate=';
$url3='&Channel=TimeSpanInSec&Channel=Current_AC_Phase_1&Channel=Current_AC_Phase_2&Channel=Current_AC_Phase_3&Channel=Current_DC_String_1&Channel=Current_DC_String_2&Channel=Digital_PowerManagementRelay_Out_1&Channel=EnergyReal_WAC_Minus_Absolute&Channel=EnergyReal_WAC_Plus_Absolute&Channel=EnergyReal_WAC_Sum_Produced&Channel=InverterErrors&Channel=InverterEvents&Channel=Meter_Location_Current&Channel=PowerReal_PAC_Sum&Channel=Temperature_Powerstage&Channel=Voltage_AC_Phase_1&Channel=Voltage_AC_Phase_2&Channel=Voltage_AC_Phase_3&Channel=Voltage_DC_String_1&Channel=Voltage_DC_String_2';
$url=$url1.$readdate.$url2.$readdatee.$url3;
//convert json object to php associative array
$data = json_decode(file_get_contents($url), true);
//get the employee details
$start =$data['Body']['Data']['inverter/1']['Start'];
echo " Gelieferte Daten für ",$start, " ... Füge Daten ein.\n";
$arrtsis = $data['Body']['Data']['inverter/1']['Data']['TimeSpanInSec']['Values'];
$arrcp1 = $data['Body']['Data']['inverter/1']['Data']['Current_AC_Phase_1']['Values'];
$arrcp2 = $data['Body']['Data']['inverter/1']['Data']['Current_AC_Phase_2']['Values'];
$arrcp3 = $data['Body']['Data']['inverter/1']['Data']['Current_AC_Phase_3']['Values'];
$arrcs1 = $data['Body']['Data']['inverter/1']['Data']['Current_DC_String_1']['Values'];
$arrcs2 = $data['Body']['Data']['inverter/1']['Data']['Current_DC_String_2']['Values'];
$arrerwsp = $data['Body']['Data']['inverter/1']['Data']['EnergyReal_WAC_Sum_Produced']['Values'];
$arrprps = $data['Body']['Data']['inverter/1']['Data']['PowerReal_PAC_Sum']['Values'];
$arrtp = $data['Body']['Data']['inverter/1']['Data']['Temperature_Powerstage']['Values'];
$arrvp1 = $data['Body']['Data']['inverter/1']['Data']['Voltage_AC_Phase_1']['Values'];
$arrvp2 = $data['Body']['Data']['inverter/1']['Data']['Voltage_AC_Phase_2']['Values'];
$arrvp3 = $data['Body']['Data']['inverter/1']['Data']['Voltage_AC_Phase_3']['Values'];
$arrvs1 = $data['Body']['Data']['inverter/1']['Data']['Voltage_DC_String_1']['Values'];
$arrvs2 = $data['Body']['Data']['inverter/1']['Data']['Voltage_DC_String_2']['Values'];
foreach($arrtsis as $key=>$tsis) {
$cp1=0; if( isset($arrcp1[$key])) { $cp1=$arrcp1[$key]; }
$cp2=0; if( isset($arrcp2[$key])) { $cp2=$arrcp2[$key]; }
$cp3=0; if( isset($arrcp3[$key])) { $cp3=$arrcp3[$key]; }
$cs1=0; if( isset($arrcs1[$key])) { $cs1=$arrcs1[$key]; }
$cs2=0; if( isset($arrcs2[$key])) { $cs2=$arrcs2[$key]; }
$erwsp=0; if( isset($arrerwsp[$key])) { $erwsp=$arrerwsp[$key]; }
$prps=0; if( isset($arrprps[$key])) { $prps=$arrprps[$key]; }
$tp=0; if( isset($arrtp[$key])) { $tp=$arrtp[$key]; }
$vp1=0; if( isset($arrvp1[$key])) { $vp1=$arrvp1[$key]; }
$vp2=0; if( isset($arrvp2[$key])) { $vp2=$arrvp2[$key]; }
$vp3=0; if( isset($arrvp3[$key])) { $vp3=$arrvp3[$key]; }
$vs1=0; if( isset($arrvs1[$key])) { $vs1=$arrvs1[$key]; }
$vs2=0; if( isset($arrvs2[$key])) { $vs2=$arrvs2[$key]; }
$datum = new DateTime($start);
$mykey=$key; //+3600;
date_add($datum,new DateInterval('PT'.$mykey.'S'));
$mydatum=$datum->format('Y-m-d H:i:s');
// echo $datum->format('d.m.Y H:i:s'), ",", $key, ", ", $tsis, ", ", $cp1, ", ", $cp2, ", ", $cp3, ", ", $cs1, ", ", $cs2, ", ", $erwsp, ", ", $prps, ", ", $tp, ", ", $vp1, ", ", $vp2, ", ", $vp3, ", ", $vs1, ", ", $vs2,"\n";
$sql="INSERT INTO `tblData` (datum, `key`, tsis, cp1, cp2, cp3, cs1, cs2, erwsp, prps, tp, vp1, vp2, vp3, vs1, vs2)
VALUES ('$mydatum', '$key', '$tsis', '$cp1', '$cp2', '$cp3', '$cs1', '$cs2', '$erwsp', '$prps', '$tp', '$vp1', '$vp2', '$vp3', '$vs1', '$vs2')";
// echo $sql, "\n";
//insert into mysql table
if(!mysqli_query($con, $sql)) {
die("\n\n Error : " . mysqli_error($con) . "\n\n");
}
}
echo "\n . . . Fertig! . . .\n\n";
?>
Es entsteht eine einzelne Tabelle tblData, welche die Spalten datum, `key`, tsis, cp1, cp2, cp3, cs1, cs2, erwsp, prps, tp, vp1, vp2, vp3, vs1 und vs2 hat. Da die Fronius intern die Werte im 5-Minuten-Takt speichert. landen die Daten in dieser Auflösung in der Datenbank.
Ich habe die Daten seit Oktober 2015 gespeichert, das sind mittlerweile etwas über 50 MByte. In der Anfangszeit hatte ich einige Male verpasst, mir die korrekten Zählerstände zu notieren, da war es ganz praktisch, über passende Abfragen zumindest näherungsweise auszurechnen, wie viel Strom die Anlage produziert hatte. Mittlerweile lasse ich aber auch die Zählerstände persistieren und kann so den Zählerstand für jeden beliebigen Zeitpunkt nachträglich ablesen
Das Script lasse ich einmal nachts per crontab ausführen, wie man sehen kann ist es quick'n' dirty zusammengeschustert, aber es funktioniert klaglos. Das lokale Archiv des Geräts ist groß genug, um die Daten mehrerer Monate vorzuhalten, deshalb kann man das Script auch mit Start- und Enddatum aufrufen. Allerdings tut man gut daran, die Daten einzeln tageweise abzuholen, die Menge an Daten wird sonst einfach zu groß und der Fronius beantwortet die Anfrage dann gar nicht.