date("Y")){ exit; } if(isset($_GET["type"])){ if(strtolower($_GET["type"]) =="lastyear"){ $_GET["year"] = date("Y")-1; }elseif(strtolower($_GET["type"]) =="prelastyear"){ $_GET["year"] = date("Y")-2; } } /** * Die Jahresstatistik als eine Abfrage - jetzt auf stats_daily. * * Gerechnet wird nicht mehr ueber die Rohdaten aus EnergyFlow, sondern ueber * die Tageswerte. Zwei Gruende: * * 1. Die Rohdaten werden nach zwoelf Monaten ausgeduennt bzw. ins * Stundenarchiv verschoben (solarlog-rollup.sh). Eine Kachel, die auf * EnergyFlow rechnet, zeigt fuer alte Jahre danach zu wenig an. * 2. Ein Jahr sind 365 Zeilen statt rund 105.000. * * Die Tarife bleiben unveraendert: je Zeile ein Stichtag, das Ende holt * LEAD() beim naechsten. Weil ein Stichtag ein DATUM ist, kann ein Tag nie * zwei Tarife haben - die Verdichtung auf Tage verliert hier also nichts. * * Was in stats_daily vorberechnet sein MUSS, weil es eine Bedingung je * Messwert auswertet und sich aus Tagessummen nicht rekonstruieren laesst: * * eigenverbrauch_kwh pv - Einspeisung - Batterieladung * - Heizstab + Batterieentladung. Dazu addiert * wird pv_fehlbetrag_kwh: bei Ausfall einzelner * Wechselrichter fehlt deren Beitrag in pv, alle * Senken sind dagegen gemessen - die Differenz * faellt sonst zu klein oder negativ aus. * heizstab_solar_kwh Heizstab, anteilig nach autonomy * auto_*_solar_kwh Wallbox, anteilig nach autonomy - dem vom * Geraet in feiner Aufloesung gerechneten * Nicht-Netz-Anteil der Zufuhr * * Einheiten sind in stats_daily bereits bereinigt: PL*_EV und PL*_EVog * liefern Kilowatt, alle uebrigen Leistungsspalten Watt. In der alten * Abfrage stand das als /12 gegen /12000 nebeneinander. * * Die Solaranteile teilen jetzt durch NULLIF(...): ohne Ladung im Jahr kam * vorher 0/0 heraus. * * "Ersparnis Batterie" rechnet den Nutzen netto: was die entladene Energie * aus dem Netz gekostet haette, abzueglich der Verguetung, die fuer den zum * Laden verwendeten Strom entgangen ist. Brutto waere die Kachel zu * freundlich - der Speicher ist nicht umsonst zu fuellen. * * Achtung beim Lesen: "Verbrauchsersparnis" ist der GESAMTE Eigenverbrauch * zum Strompreis. "Ersparnis Batterie" und "Ersparnis Solarladung" sind * Teilmengen davon, nach Herkunft bzw. Verwendung herausgegriffen. Sie * duerfen nicht addiert werden. * * Der Grundpreis fehlt weiterhin bewusst - er haengt an den Tagen des * Jahres, nicht an einem Messwert, und kommt aus grundpreisImJahr() dazu. */ function statistikAbfrage($jahr) { return "WITH preis AS (SELECT active_date, cost, gain, LEAD(active_date) OVER (ORDER BY active_date) AS folgt FROM gridCosts), gas AS (SELECT active_date, cost, kwhPerLitre, LEAD(active_date) OVER (ORDER BY active_date) AS folgt FROM gasCosts), sprit AS (SELECT active_date, cost, lPer100km, kwhPer100km, LEAD(active_date) OVER (ORDER BY active_date) AS folgt FROM fuelCosts) SELECT SUM(d.netz_bezug_kwh) AS 'Stromverbrauch', SUM(d.netz_bezug_kwh * preis.cost) AS 'Stromkosten', SUM((d.eigenverbrauch_kwh + IFNULL(d.pv_fehlbetrag_kwh,0)) * preis.cost) AS 'Verbrauchsersparnis', SUM(d.netz_einsp_kwh * preis.gain) AS 'Einspeisevergütung', SUM(d.heizstab_solar_kwh * gas.cost / NULLIF(gas.kwhPerLitre,0)) AS 'Ersparnis Heizung', SUM(d.batt_entladen_kwh * preis.cost - d.batt_laden_kwh * preis.gain) AS 'Ersparnis Batterie', SUM(d.autarkie_avg * d.stunden_erfasst) / NULLIF(SUM(d.stunden_erfasst),0) AS 'Ø Autarkie', SUM(d.auto_eg_kwh) AS 'Autoladung ges. EG', SUM(d.auto_eg_solar_kwh) / NULLIF(SUM(d.auto_eg_kwh),0) * 100 AS 'Autoladung Solar EG', SUM(d.auto_eg_solar_kwh * preis.cost) AS 'Ersparnis Solarladung EG', SUM(d.auto_eg_kwh * sprit.lPer100km / NULLIF(sprit.kwhPer100km,0)) AS 'Benzin gespart EG', SUM(d.auto_eg_kwh * sprit.lPer100km / NULLIF(sprit.kwhPer100km,0) * sprit.cost) AS 'Ersparnis Benzin EG', SUM(d.auto_og_kwh) AS 'Autoladung ges. OG', SUM(d.auto_og_solar_kwh) / NULLIF(SUM(d.auto_og_kwh),0) * 100 AS 'Autoladung Solar OG', SUM(d.auto_og_solar_kwh * preis.cost) AS 'Ersparnis Solarladung OG', SUM(d.auto_og_kwh * sprit.lPer100km / NULLIF(sprit.kwhPer100km,0)) AS 'Benzin gespart OG', SUM(d.auto_og_kwh * sprit.lPer100km / NULLIF(sprit.kwhPer100km,0) * sprit.cost) AS 'Ersparnis Benzin OG' FROM stats_daily d JOIN preis ON d.tag >= preis.active_date AND (preis.folgt IS NULL OR d.tag < preis.folgt) LEFT JOIN gas ON d.tag >= gas.active_date AND (gas.folgt IS NULL OR d.tag < gas.folgt) LEFT JOIN sprit ON d.tag >= sprit.active_date AND (sprit.folgt IS NULL OR d.tag < sprit.folgt) WHERE YEAR(d.tag) = " . intval($jahr) . ";"; } $Query = statistikAbfrage($_GET["year"]); $PrevQuery = statistikAbfrage($_GET["year"] - 1); // Reihenfolge wie in der Abfrage, mit "Verg.+Einsp. Strom" an Stelle 4. $units = Array("kWh","€","€","€","€","€","€","%", "kWh","%","€","L","€", "kWh","%","€","L","€"); // Nur bei Verbrauch und Kosten ist weniger besser. $LessIsBetter = array_merge([true, true], array_fill(0, count($units) - 2, false)); function array_insert($array,$values,$offset) { return array_slice($array, 0, $offset, true) + $values + array_slice($array, $offset, NULL, true); } if (checkLogin()) { $html = "
"; $mysql = solarDb(); $Res = mysqli_query($mysql,$Query); $ResPrev = mysqli_query($mysql,$PrevQuery); if(!$Res || !$ResPrev){ echo "Error:
".mysqli_error($mysql)."
"; } if ($Res->num_rows > 0) { $i = 0; $row = $Res->fetch_assoc(); $rowPrev = $ResPrev->fetch_assoc(); // Der Grundpreis faellt unabhaengig vom Verbrauch an und laesst sich // deshalb nicht aus den Messwerten summieren. $row["Stromkosten"] += grundpreisImJahr($_GET["year"]); $rowPrev["Stromkosten"] += grundpreisImJahr($_GET["year"] - 1); //$row["Vergütung+Einsparung Strom"] = $row["Einspeisevergütung"]+$row["Verbrauchsersparnis"]; $row = array_insert($row,["Verg.+Einsp. Strom" => $row["Einspeisevergütung"]+$row["Verbrauchsersparnis"]],4); $rowPrev = array_insert($rowPrev,["Verg.+Einsp. Strom" => $rowPrev["Einspeisevergütung"]+$rowPrev["Verbrauchsersparnis"]],4); $i = 0; foreach ($row as $name => $value) { if(str_starts_with($name,"Autoladung ges.")){ $html .= "

"; $html .= "
"; } /*$html .= "
".$name." ". number_format(floatval($value),2,",",".") ."".$units[$i++]."
";*/ $html .= "
".$name."
"; $i++; } } $html .= "
"; } //header('Content-Type: application/json'); echo $html; //echo '{"labels":[1761322682000,1761322782000,1761322882000,1761322982000,1761323082000,1761323182000,1761323282000],"datasets":[{"stack": "Stack 0","cubicInterpolationMode":"monotone","fill":"origin","label":"Acquisitions by year","data":[10,20,50,20,10,5,70]},{"fill": "false","stack": "Stack 1","cubicInterpolationMode": "monotone","label": "Acquisitions by year","data": [10,20,50,20,10,5,70]}]}';