Visualisierung der Zählerwerte
Allgemeine Informationen
Auf dieser Seite wird eine Beispielvisualisierung von Zählerdaten präsentiert. Die gezeigten Werte sind bewusst eingeschränkt, repräsentieren jedoch realitätsnahe Datenstrukturen. Ziel ist es, eine intuitive Darstellung und Auswertung von Verbrauchs- und Einspeisewerten zu ermöglichen. Der vollständige Quellcode der Visualisierung steht im Anschluss zur Verfügung. Die zugrundeliegende Datenbasis wird aus einer MySQL-Datenbank geladen, welche idealerweise von einem Mikrocontroller (z.B. Arduino) regelmäßig gespeist wird.Inhaltsverzeichnis
-
Weitere verwandte Themen:
- SML Protokoll verstehen
- Vom Arduino in die MySql Datenbank (siehe Programme/Projekte)
Beispiel Visualisierung
Die Zählerwerte sind für die Öffentlichkeit stark eingeschränkt und nicht zu 100 % realistisch. Sie sollen als Beispiel dienen und Möglichkeiten aufzeigen. Der aktuell verfügbare Datensatz umfasst den Zeitraum vom 24.09.2025 bis zum 03.11.2025.
Aktuelle Zählerwerte
Werte in der Tabelle werden nach Auswahl eines Datums neu eingelesen. Alle 60 Sekunden wird der aktuelle Verbrauch in Watt aktualisiert. Werte die sich ändern, leuchten kurz Rot auf.
| Datum: | |
| Werte für OBIS 1.8.0 | |
| Zählerstand: | kWh |
| Tagesverbrauch: | kWh |
| Werte für OBIS 2.8.0 | |
| Zählerstand: | kWh |
| Tageseinspeisung: | kWh |
| Werte für OBIS 10.07.0 | 60 Sek. bis Update |
| Aktuelle Leistung: | Watt |
| Zeitstempel: | Uhr |
Graph Stromzähler Daten
Kurze Funktionsbeschreibung
Die Visualisierung besteht aus dynamischen Diagrammen, Tabellen und interaktiven Steuerelementen. Daten werden per AJAX von der Datenbank geladen und mit JavaScript aktualisiert. In der Tabelle werden die aktuellen Zählerstände und Verbrauchswerte zum jeweiligen Datum angezeigt. Werte aus der Vergangenheit können über das Datum ausgewählt werden. Der Wert für den aktuellen Verbrauch oder die Einspeisung wird alle 60 Sekunden automatisch aktualisiert.
- Donut-Diagramm: Aktuelle Leitung in Watt
Die aktuelle Leistung in Watt wird in einem Donut-Diagramm angezeigt. Ist der Donut grün (negativer Wert), liegt eine Einspeisung vor. Bei den Farben Gelb und Rot liegt ein Netzbezug vor. Die automatische Aktualisierung erfolgt alle 60 Sekunden. - Balkendiagramme: Übersicht Tagesverbräuche in KWH
In diesem Diagramm sind die summierten Tagesverbräuche (blau) und Einspeisewerte (grün) des jeweils ausgewählten Monats in kWh dargestellt. - Balkendiagramme: Übersicht Monatsverbräuche in KWH
In diesem Diagramm sind die summierten Monatsverbräuche (blau) und Einspeisewerte (grün) des jeweils ausgewählten Jahres in kWh dargestellt.
- Balkendiagramme: Übersicht Jahresverbräuche in KWH
In diesem Diagramm sind die summierten Jahresverbräuche (blau) und Einspeisewerte (grün) in kWh dargestellt. - Liniendiagramm: Tagesauswertung
In diesem Liniendiagramm wird die verbrauchte und eingespeiste Leistung in Watt in Abhängigkeit zur Zeitachse für den jeweiligen Tag angezeigt. Wird diese Ansicht ausgewählt, können über die Datumsauswahl in der Tabelle die Daten für den jeweiligen Tag angezeigt werden.
Quellcode Visualisierung
Die Visualisierung basiert auf der Bibliothek graph.js (Version 2.5.0).
Zur Anzeige von Meldungen wird sweetalert2 verwendet.
Die Daten werden über PHP aus einer MySQL-Datenbank geladen.
Voraussetzung sind vorbereitete SQL-Tabellen mit OBIS-Daten.
Weitere Infos findest du unter: `Vom Arduino in die MySql Datenbank.`
PHP Quellcode Grenzwertermittlung
Dieser PHP-Code ermittelt das Start- und Enddatum der verfügbaren Messwerte.
Daraus werden z.B. Dropdown-Auswahlfelder für Jahre und gültige Datumsbereiche generiert.
Es erfolgt eine SQL-Abfrage auf die Tabelle obis_180_280, um das erste und letzte Messdatum zu laden.
Danach werden die Daten als Array aufbereitet und für die HTML-Ausgabe vorbereitet.
/* Datenbankverbindung */
include 'dbcon.php'; // Siehe SQL Verbindung oben
/* Abfrage Steuerdaten */
$parts_end_ymd = "";
$parts_start_ymd = "";
$option_yyyy_kwh = "";
$statement = "SELECT * FROM obis_180_280 WHERE date = (SELECT MIN(date) FROM obis_180_280)
UNION
SELECT * FROM obis_180_280 WHERE date = (SELECT MAX(date) FROM obis_180_280);";
$sqlresult = mysqli_query($dbcon, $statement);
if ($sqlresult && mysqli_num_rows($sqlresult) > 0) {
// Schleife für alle Datensätze (in diesem Fall 2)
while ($dsatzSQL = mysqli_fetch_assoc($sqlresult)) {
// Speichern der Daten im Array
$DBdataArray[] = $dsatzSQL;
}
// Sicherstellen, dass genau 2 Datensätze im Array sind
if (count($DBdataArray) == 2) {
$parts_start_ymd = explode("-", $DBdataArray[0]["date"]);
$parts_end_ymd = explode("-", $DBdataArray[1]["date"]);
} elseif(count($DBdataArray) == 1) {
$parts_start_ymd = explode("-", $DBdataArray[0]["date"]);
$parts_end_ymd = explode("-", $DBdataArray[0]["date"]);
}else{
echo "kein Datensatz";
}
// Dropdown Jahresauswahl
for ($i = $parts_start_ymd[0]; $i <= $parts_end_ymd[0]; $i++) {
$selected = ($i == $parts_end_ymd[0]) ? " selected" : "";
$option_yyyy_kwh .= "<option value=\"$i\"$selected>$i</option>";
}
}
/* Verbindung zur SQL-DB trennen */
mysqli_close($dbcon);
Datenbankverbindung dbcon.php
Diese Datenbankverbindung wird für alle SQL-Abfragen benötigt und muss daher in jede PHP-Datei eingebunden include "dbcon.php"; werden.
/* Datenbankverbindung */
$username = "XXX";
$password = "AAA";
$database = "YYY";
$hostname = "CCC";
//connection to the database
$dbcon_sh = mysqli_connect($hostname, $username, $password, $database);
mysqli_set_charset($dbcon, 'utf8');
HTML Seitenaufbau
Das HTML stellt den strukturellen Rahmen der Seite bereit. Inhalte wie Datumsauswahl, Tabellenstruktur und Platzhalter für Diagramme sind hier definiert. Dynamische Inhalte werden per JavaScript und PHP befüllt.
<section>
<h2>Visualisierung</h2>
<div class="row gtr-200">
<div class="col-6 col-12-medium">
<h3>Aktuelle Zählerwerte</h3>
<p>
Werte in der Tabelle werden nach Auswahl eines Datums neu eingelesen.
Alle 60 Sekunden wird der aktuelle Verbrauch in Watt aktualisiert.
Werte die sich ändern, leuchten kurz Rot auf.
</p>
<div class="table-wrapper">
<table class="alt">
<tbody>
<tr>
<td>Datum:</td>
<td>
<input id="input_date_180_280" type="date" value="'.$parts_end_ymd[0].'-'.$parts_end_ymd[1].'-'.$parts_end_ymd[2].'" min="'.$parts_start_ymd[0].'-'.$parts_start_ymd[1].'-'.$parts_start_ymd[2].'" max="'.$parts_end_ymd[0].'-'.$parts_end_ymd[1].'-'.$parts_end_ymd[2].'" onchange="get_180_280(this.value)">
</td>
</tr>
<tr>
<td colspan="2">
<b>Werte für OBIS 1.8.0</b>
</td>
</tr>
<tr>
<td>Zählerstand:</td>
<td id="value_obis180"> kWh</td>
</tr>
<tr>
<td>Tagesverbrauch:</td>
<td id="used_obis180"> kWh</td>
</tr>
<tr>
<td colspan="2">
<b>Werte für OBIS 2.8.0</b>
</td>
</tr>
<tr>
<td>Zählerstand:</td>
<td id="value_obis280"> kWh</td>
</tr>
<tr>
<td>Tageseinspeisung:</td>
<td id="used_obis280"> kWh</td>
</tr>
<tr>
<td><b>Werte für OBIS 10.07.0</b></td>
<td><span id="sek_to_update_10070">60</span> Sek. bis Update</td>
</tr>
<tr>
<td>Aktuelle Leistung:</td>
<td id="value_obis10070"> Watt</td>
</tr>
<tr>
<td>Zeitstempel:</td>
<td id="time_obis10070"> Uhr</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-6 col-12-medium">
<h3>Graph Stromzähler Daten</h3>
<select id="drop_Funktion" onchange="loadDynamicContent()">
<option value="option1" selected>Aktuelle Leistung in Watt</option>
<option value="option2" >Übersicht Tagesverbräuche in KWH</option>
<option value="option3" >Übersicht Monatsverbräuche in KWH</option>
<option value="option4" >Übersicht Jahresverbräuche in KWH</option>
<option value="option5" >Tagesauswertung</option>
</select>
<div id="dynamicContent">
<!-- Der dynamisch geladene Inhalt erscheint hier -->
</div>
<canvas id="Option_Graph" width="100%" height="100%"></canvas>
</div>
</div>
<section>
Variablenübergabe php --> JS
Zur Übergabe von PHP-Daten an JavaScript werden <script>-Blöcke verwendet, in denen PHP-Werte als Konstanten definiert werden.
Dies erlaubt z.B. die Steuerung der Datumsauswahl.
<!-- Übergabe von PHP-Daten an JavaScript -->
<script>
const partsEndYmd = "<?php echo implode('-', $parts_end_ymd); ?>"; // z.B. "2025-09-29"
const partsEndYm = "<?php echo $parts_end_ymd[0] . '-' . $parts_end_ymd[1]; ?>"; // z.B. "2025-09"
const partsStartYm = "<?php echo $parts_start_ymd[0] . '-' . $parts_start_ymd[1]; ?>"; // z.B. "2023-01"
const partsStartYear = "<?php echo $parts_start_ymd[0]; ?>"; // z.B. "2023"
const partsEndYear = "<?php echo $parts_end_ymd[0]; ?>"; // z.B. "2025"
const optionYyyyKwh = `<?php echo $option_yyyy_kwh; ?>`; // HTML <option>-Elemente für das Jahr
</script>
Javasqript Start Umgebung
Beim Laden der Seite werden mittels DOMContentLoaded initiale Daten geladen und Event-Handler gesetzt.
Dadurch ist die Anwendung sofort nutzbar.
Zusätzlich werden hier die dynamischen Elemente angesteuert, nachdem die jeweilige Funktionsart ausgewählt wurde.
//Skripte Laden nach Seitenaufbau-->
document.addEventListener("DOMContentLoaded", function () {
loadDynamicContent(); //Laden der Daten für die Funktionsauswahl
get_180_280(partsEndYmd); // Laden der Daten für Tabelle obis 180 und 280
});
//Load Dynamik Content
// JSON-Daten mit HTML-Struktur und optionalem AJAX-Aufruf (ohne Chart)
const contentData = {
"option1": `<br>
<p>
Anzeige der aktuellen Leistung der Einspeisung oder Bezug in Watt.
</p>`,
"option2": `<br>
<p>
Es werden die Verbräuche in kWh für den jeweiligen Tag des ausgewählten Zeitraums angezeigt.
</p>
<div class="table-wrapper">
<table class="alt">
<tbody>
<tr>
<td>Bitte Monat wählen:</td>
<td><input type="month" id="yyyy_mm_kwh" value="${partsEndYm}" min="${partsStartYm}" max="${partsEndYm}" onchange="load_graph_option_2_3_4(this.value)"></td>
</tr>
</tbody>
</table>
</div>`,
"option3": `<br>
<p>
Es werden die Verbräuche in kWh für den jeweiligen Monat des ausgewählten Jahres angezeigt.
</p>
<label for="yyyy_kwh">Jahr auswählen:</label>
<select id="yyyy_kwh" onchange="load_graph_option_2_3_4(this.value)">
${optionYyyyKwh}
</select>`,
"option4": `<br>
<p>
Es werden die Verbräuche der letzten Jahre angezeigt. Aktueller Anzeigzeitraum ${partsStartYear} - ${partsEndYear}
</p>`,
"option5": `<br>
<p>
Detailierte Tagesansicht zum Bezug und zur Einspeisung für das ausgewählte Datum (siehe Tabelle).
</p>`,
};
function loadDynamicContent() {
const selectedValue = document.getElementById("drop_Funktion").value;
if (selectedValue === "") {
document.getElementById("dynamicContent").innerHTML = "";
return;
}
const content = contentData[selectedValue];
if (content) {
if (typeof content === "string") {
document.getElementById("dynamicContent").innerHTML = content;
} else if (typeof content === "object") {
document.getElementById("dynamicContent").innerHTML = content.html;
if (content.fetchData) {
content.fetchData();
}
}
}
const selectedOption = document.getElementById("drop_Funktion").value; // Die ausgewählte Option im Dropdown-Menü
switch (selectedOption) {
case "option1":
get_10070();
countdown(true);
break;
case "option2":
load_graph_option_2_3_4();
break;
case "option3":
load_graph_option_2_3_4();
break;
case "option4":
load_graph_option_2_3_4();
break;
case "option5":
load_graph_option5();
break;
}
}
JS AJAX Tabellenfunktionen
Mittels AJAX werden aktuelle Verbrauchs- und Einspeisewerte geladen. Die zugehörigen PHP-Skripte liefern JSON-Daten, die dann in die Tabelle eingefügt werden. Die Zuordnung erfolgt über den Dateinamen.
Tabellendaten OBIS 10.07.00
Diese Daten repräsentieren die aktuelle elektrische Leistung in Watt, die vom Stromzähler alle 60 Sekunden gemessen wird. Sie wird live in der Oberfläche angezeigt und ist Grundlage für die Darstellung im Donut-Diagramm (Option 1).
//Get 10.07.0 last value
function get_10070() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var ajaxresultsplit = this.responseText.split("|");
changeCellContent("value_obis10070", ajaxresultsplit[0] + " Watt");
changeCellContent("time_obis10070", ajaxresultsplit[1]);
checkTimestamp(ajaxresultsplit[1]);
// Den Graph nur laden wenn option1 aktiv
const selectedOption = document.getElementById("drop_Funktion").value; // Die ausgewählte Option im Dropdown-Menü
if (selectedOption == "option1") {
load_graph_option1(ajaxresultsplit[0]);
}
}
};
xmlhttp.open("GET", "get_10070.php", true);
xmlhttp.send();
}
Aufbau der Datei get_10070.php
Diese PHP-Datei liest den zuletzt gespeicherten Wert des OBIS-Kennwerts 10.07.0 aus der Datenbanktabelle obis_10070.
Die Daten (Leistung in Watt und Zeitstempel) werden als JSON zurückgegeben, sodass sie per AJAX in die Seite eingebunden werden können.
<?php
/* Datenbankverbindung */
include 'dbcon.php'; // Siehe SQL Verbindung oben
$ajaxresult = "";
// SQL-Abfrage (bereinigter Variablenname!)
$statement = "SELECT obis_10070, TimeStamp
FROM obis_10070
ORDER by TimeStamp DESC
LIMIT 1";
$sqlresult = mysqli_query($dbcon, $statement);
if ($sqlresult && mysqli_num_rows($sqlresult) > 0) {
$dsatzSQL = mysqli_fetch_assoc($sqlresult);
$ajaxresult = implode('|', [
$dsatzSQL["obis_10070"],
$dsatzSQL["TimeStamp"]
]);
}
/* Verbindung zur SQL-DB trennen */
mysqli_close($dbcon);
/* Rückgabewert */
echo $ajaxresult;
?>
Tabellendaten OBIS 1.8.0 und 2.8.0
Diese Daten zeigen den Stromverbrauch (1.8.0) und die Einspeisung (2.8.0) pro Tag an. In der Tabelle werden der Gesamtzählerstand und der Tageswert angezeigt. Die Datenbasis dient außerdem für die Grafiken (Option 2–5).
//Get 180 280 by Date
function get_180_280(ymd_obis_180_280) {
if (ymd_obis_180_280.length == 0) {
return;
} else {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var ajaxresultsplit = this.responseText.split("|");
changeCellContent("used_obis180", ajaxresultsplit[0] + " KWh");
changeCellContent("value_obis180", ajaxresultsplit[1] + " KWh");
changeCellContent("used_obis280", ajaxresultsplit[2] + " KWh");
changeCellContent("value_obis280", ajaxresultsplit[3] + " KWh");
}
};
xmlhttp.open("GET", "get_180_280.php?ymd_obis_180_280=" + ymd_obis_180_280, true);
xmlhttp.send();
}
// Den Graph nur laden wenn option5 aktiv
const selectedOption = document.getElementById("drop_Funktion").value; // Die ausgewählte Option im Dropdown-Menü
if (selectedOption == "option5") {
load_graph_option5();
}
}
Aufbau der Datei get_180_280.php
Diese PHP-Datei lädt die Tageswerte zu einem bestimmten Datum für die OBIS-Codes 1.8.0 (Verbrauch) und 2.8.0 (Einspeisung).
Die Werte werden aus der Tabelle obis_180_280 selektiert und als JSON an JavaScript zurückgegeben, um die Tabelle auf der Webseite zu befüllen.
<?php
/* Datenbankverbindung */
include 'dbcon.php'; // Siehe SQL Verbindung oben
// Eingabewert holen und absichern
$ymd_obis_180_280 = $_REQUEST["ymd_obis_180_280"] ?? '';
// Frühzeitiger Abbruch, wenn kein Datum übergeben wurde
if (empty($ymd_obis_180_280)) {
echo 'Kein Wert|Kein Wert|Kein Wert|Kein Wert';
mysqli_close($dbcon);
exit;
}
$ajaxresult = "";
// SQL-Abfrage (bereinigter Variablenname!)
$statement = "SELECT used_180, used_280, obis_180, obis_280
FROM obis_180_280
WHERE date = '" . $ymd_obis_180_280 . "'
LIMIT 1";
$sqlresult = mysqli_query($dbcon, $statement);
if ($sqlresult && mysqli_num_rows($sqlresult) > 0) {
$dsatzSQL = mysqli_fetch_assoc($sqlresult);
$ajaxresult = implode('|', [
$dsatzSQL["used_180"],
$dsatzSQL["obis_180"],
$dsatzSQL["used_280"],
$dsatzSQL["obis_280"]
]);
}
/* Verbindung zur SQL-DB trennen */
mysqli_close($dbcon);
/* Rückgabewert */
echo $ajaxresult;
?>
Allgemeine Unterstützungfunktionen
Diese JavaScript-Hilfsfunktionen kümmern sich um die Aktualisierung von Zellen, Zeitmessung und Plausibilitätsprüfungen:
- changeCellContent(...): Aktualisiert dynamisch den Zellinhalt und markiert Änderungen visuell.
- countdown(...): Zählt die verbleibenden Sekunden bis zur nächsten Datenaktualisierung herunter.
- checkTimestamp(...): Prüft, ob der letzte Zeitstempel zu alt ist, und zeigt ggf. eine Warnung an.
//Werte an id der Tabelle übergeben
function changeCellContent(cellId, newContent) {
var cell = document.getElementById(cellId);
// Ändern Sie den Zelleninhalt
const [intPart, decPart] = newContent.toString().split('.');
cell.innerHTML = `<strong>${intPart}</strong>${decPart ? ',' + decPart : ''}`;
// Ändern Sie die Hintergrundfarbe allmählich
var originalBackgroundColor = getComputedStyle(cell).backgroundColor || "";
cell.style.transition = "background-color 1s ease"; // Übergangseffekt für die Farbänderung
cell.style.backgroundColor = "#ff9680";
// Setzen Sie nach einer Verzögerung die Hintergrundfarbe zurück
setTimeout(function() {
cell.style.backgroundColor = originalBackgroundColor;
cell.style.transition = ""; // Zurücksetzen der Übergangseigenschaft
}, 1000); // 1000 Millisekunden = 1 Sekunde
}
//Interval zum Laden der Werte für Option 1
let countdownInterval;
let timeLeft = 60;
function countdown(reset = false) {
if (reset) {
clearInterval(countdownInterval);
timeLeft = 60;
}
if (!countdownInterval || reset) {
countdownInterval = setInterval(() => {
document.getElementById("sek_to_update_10070").innerText = timeLeft;
timeLeft--;
if (timeLeft < 0) {
timeLeft = 60; // automatisch wieder von vorn
get_10070(); // Nach ablauf der Zeit die aktuellen Werte für Tabelle abrufen
}
}, 1000);
}
}
//Check Timestamp
function checkTimestamp(timestampString) {
// Timestamp in ISO-Format umwandeln
const timestamp = new Date(timestampString.replace(" ", "T"));
const now = new Date();
const diffMs = now - timestamp; // Differenz in Millisekunden
const maxDiffMs = 5 * 1000 * 60;
if (diffMs > maxDiffMs) {
Swal.fire({
icon: 'error',
title: 'Zeitüberschreitung',
text: `Der angegebene Timestamp liegt mehr als ${maxDiffMs / 1000} Sekunden in der Vergangenheit.`,
});
}
}
JS AJAX Graphfunktionen
Diese Funktionen erzeugen die verschiedenen Diagrammtypen (Donut, Balken, Linien) auf Basis dynamisch geladener Daten aus der Datenbank. Die Daten werden per AJAX von zugehörigen PHP-Dateien im JSON-Format bezogen. Die jeweilige Option (1–5) bestimmt dabei den Diagrammtyp und die Quelle der Auswertung.
Option 1: Donut
Zeigt die aktuelle Leistung (Verbrauch oder Einspeisung) als Donut-Diagramm. Die Farbgebung signalisiert den Zustand:
- Grün: Einspeisung (negativer Wert)
- Gelb oder Rot: Stromverbrauch
//Graph Funktionen
function load_graph_option1(obis_10070_value) {
obis_10070_value = Number(obis_10070_value);
if (window.myChart) {
window.myChart.destroy();
}
//Daten für Graph erzeugen
let graph_labels = [];
let graph_colors = [];
let graph_values = [];
let hidden_values = [10000, 1000];
if (obis_10070_value >= 0){
if (obis_10070_value <= hidden_values[0]/2){
graph_values[0] = obis_10070_value;
graph_values[1] = hidden_values[0] - obis_10070_value;
graph_labels = [obis_10070_value + " Watt Bezug"];
graph_colors = ["yellow", "#FFFFFF"];
}else{
graph_values[0] = hidden_values[0]/2;
graph_values[1] = obis_10070_value - hidden_values[0]/2;
graph_values[2] = hidden_values[0]/2 - graph_values[1];
graph_labels = ["",obis_10070_value + " Watt Bezug",""];
graph_colors = ["yellow", "red", "#FFFFFF"];
}
}else{
graph_values[0] = obis_10070_value * -1;
graph_values[1] = hidden_values[1] + obis_10070_value;
graph_labels = [obis_10070_value + " Watt Einspeisung"];
graph_colors = ["green", "#FFFFFF"];
}
//Graph erzeugen
var ctx = document.getElementById("Option_Graph").getContext("2d");
window.myChart = new Chart(ctx, {
type: "doughnut",
data: {
labels: graph_labels,
datasets: [{
data: graph_values, // Beispielwerte
backgroundColor: graph_colors,
borderWidth: 0
}]
},
options: {
rotation: -Math.PI, // Start links
circumference: Math.PI, // nur oberer Halbkreis
cutoutPercentage: 50, // Donut-Loch (2.x Syntax)
responsive: true,
maintainAspectRatio: true, // Höhe kontrollieren
legend: {position: "top"},
tooltips: {enabled: false},
hover: {mode: null},
animation: {duration: 3000}
}
});
}
Option 2, 3 und 4: Balkendiagramme
Diese Optionen zeigen historische Verbrauchs- und Einspeisewerte als Balkendiagramm:
- Option 2: Tageswerte eines Monats
- Option 3: Monatswerte eines Jahres
- Option 4: Jahresübersicht über mehrere Jahre
//Graph Funktionen
function load_graph_option_2_3_4(date_for_query = "") {
// Alten Graph löschen
if (window.myChart) {
window.myChart.destroy();
}
// Wenn leer oder undefined, aktuelles Datum nehmen
let now = new Date();
let year = now.getFullYear();
let month = String(now.getMonth() + 1).padStart(2, "0");
const selectedOption = document.getElementById("drop_Funktion").value; // Die ausgewählte Option im Dropdown-Menü
let ajaxurl = "";
if (selectedOption == "option2") {
ajaxurl = "get_180_280_days.php";
if (!date_for_query) {
date_for_query = `${year}-${month}`;
}
}else if (selectedOption == "option3"){
ajaxurl = "get_180_280_months.php";
if (!date_for_query) {
date_for_query = `${year}`;
}
}else if (selectedOption == "option4"){
ajaxurl = "get_180_280_years.php";
}
// AJAX-Anfrage
$.ajax({
url: ajaxurl,
type: "GET",
dataType: "json",
data: {
setdate_for_query: date_for_query
},
success: function(data) {
// Zugriff auf die Arrays
let graph_data_used280 = data.arr_used280;
let graph_data_used180 = data.arr_used180;
let graph_labels = data.arr_date;
// Neuen Graph erstellen – JETZT SIND DIE DATEN DA
var ctx = document.getElementById("Option_Graph").getContext("2d");
window.myChart = new Chart(ctx, {
type: "bar",
data: {
labels: graph_labels,
datasets: [
{
label: "Einspeisung in KWH",
data: graph_data_used280,
backgroundColor: "green",
stack: "Stack 0"
},
{
label: "Bezug in KWH",
data: graph_data_used180,
backgroundColor: "blue",
stack: "Stack 0"
}
]
},
options: {
scales: {
x: {
stacked: true
},
y: {
stacked: true
}
}
}
});
},
error: function(xhr, status, error) {
console.error("Fehler bei der AJAX-Anfrage:", error);
}
});
}
Aufbau der Datei get_180_280_days.php
Diese Datei berechnet die Tagesverbräuche und Einspeisungen eines ausgewählten Monats. Sie führt eine SQL-Abfrage durch, summiert die Werte je Tag und gibt das Ergebnis als JSON zurück. Basis für Option 2 (Tagesdiagramm).
<?php
/* Datenbankverbindung */
include 'dbcon.php'; // Siehe SQL Verbindung oben
$date_for_query = $_GET['setdate_for_query'];
$statement = "SELECT used_180, used_280, date
FROM obis_180_280
WHERE date like '$date_for_query%'
ORDER by date ASC";
$sqlresult = mysqli_query($dbcon, $statement);
// Arrays vorbereiten
$arr_used180 = []; // Für used_180
$arr_used280 = []; // Für used_280
$arr_date = []; // Für date
// Ergebnis durchlaufen und Werte in Arrays speichern
while ($row = mysqli_fetch_assoc($sqlresult)) {
$arr_used180[] = $row['used_180'];
$arr_used280[] = "-".$row['used_280'];
$dateObj = new DateTime($row['date']);
$arr_date[] = $dateObj->format('d');
}
/* Verbindung zur SQL-DB trennen */
mysqli_close($dbcon);
// Die Arrays in ein assoziatives Array packen
$data = [
'arr_used180' => $arr_used180,
'arr_used280' => $arr_used280,
'arr_date' => $arr_date
];
// Setze den Content-Type auf JSON
header('Content-Type: application/json');
// Sende die Daten als JSON zurück
echo json_encode($data);
?>
Aufbau der Datei get_180_280_months.php
Diese PHP-Datei aggregiert die Monatsdaten eines ausgewählten Jahres. Sie summiert Verbrauch und Einspeisung je Monat und liefert die Daten als JSON für die Balkendiagramm-Darstellung in Option 3.
<?php
/* Datenbankverbindung */
include 'dbcon.php'; // Siehe SQL Verbindung oben
$date_for_query = $_GET['setdate_for_query'];
$statement = "
SELECT
MONTH(`date`) AS monat,
SUM(used_180) AS sum_used_180,
SUM(used_280) AS sum_used_280
FROM
obis_180_280
WHERE
YEAR(`date`) = $date_for_query
GROUP BY
MONTH(`date`)
ORDER BY
monat
";
$sqlresult = mysqli_query($dbcon, $statement);
// Arrays vorbereiten
$arr_used180 = []; // Für used_180
$arr_used280 = []; // Für used_280
$arr_date = []; // Für date
$monatsnamen = array( 1=>"Jan", 2=>"Feb", 3=>"Mrz", 4=>"Apr", 5=>"Mai", 6=>"Jun", 7=>"Jul", 8=>"Aug", 9=>"Sep", 10=>"Okt", 11=>"Nov", 12=>"Dez");
// Ergebnis durchlaufen und Werte in Arrays speichern
if ($sqlresult) {
while ($row = mysqli_fetch_assoc($sqlresult)) {
$arr_date[] = $monatsnamen[(int)$row['monat']];
$arr_used180[] = (float)$row['sum_used_180'];
$arr_used280[] = (float)$row['sum_used_280']*-1;
}
mysqli_free_result($sqlresult);
}
/* Verbindung zur SQL-DB trennen */
mysqli_close($dbcon);
// Die Arrays in ein assoziatives Array packen
$data = [
'arr_used180' => $arr_used180,
'arr_used280' => $arr_used280,
'arr_date' => $arr_date
];
// Setze den Content-Type auf JSON
header('Content-Type: application/json');
// Sende die Daten als JSON zurück
echo json_encode($data);
?>
Aufbau der Datei get_180_280_years.php
Diese Datei stellt Jahresverbräuche über mehrere Jahre hinweg zusammen. Die Daten werden pro Jahr aus der Datenbank geladen, aufsummiert und per JSON für Option 4 bereitgestellt.
<?php
/* Datenbankverbindung */
include 'dbcon.php'; // Siehe SQL Verbindung oben
$date_for_query = $_GET['setdate_for_query'];
$statement = "
SELECT
YEAR(`date`) AS year,
SUM(used_180) AS sum_used_180,
SUM(used_280) AS sum_used_280
FROM
obis_180_280
GROUP BY
YEAR(`date`)
ORDER BY
YEAR
";
$sqlresult = mysqli_query($dbcon, $statement);
// Arrays vorbereiten
$arr_used180 = []; // Für used_180
$arr_used280 = []; // Für used_280
$arr_date = []; // Für date
// Ergebnis durchlaufen und Werte in Arrays speichern
if ($sqlresult) {
while ($row = mysqli_fetch_assoc($sqlresult)) {
$arr_date[] = (int)$row['year'];
$arr_used180[] = (float)$row['sum_used_180'];
$arr_used280[] = (float)$row['sum_used_280']*-1;
}
mysqli_free_result($sqlresult);
}
/* Verbindung zur SQL-DB trennen */
mysqli_close($dbcon);
// Die Arrays in ein assoziatives Array packen
$data = [
'arr_used180' => $arr_used180,
'arr_used280' => $arr_used280,
'arr_date' => $arr_date
];
// Setze den Content-Type auf JSON
header('Content-Type: application/json');
// Sende die Daten als JSON zurück
echo json_encode($data);
?>
Option 5: Liniendiagramm
Diese Option visualisiert die zeitliche Entwicklung von Verbrauch und Einspeisung innerhalb eines einzelnen Tages. Die Messwerte werden in kurzen Abständen (z. B. 5 Minuten) aus der Datenbank geladen und als Linienverlauf angezeigt.
//Graph Funktionen
function load_graph_option5() {
// Alten Graph löschen
if (window.myChart) {
window.myChart.destroy();
}
// Datum aus Datumsauswahl beziehen
let date_for_query = document.getElementById("input_date_180_280").value;
// AJAX-Anfrage
$.ajax({
url: "ajax/sh_get_10070_date.php",
type: "GET",
dataType: "json",
data: {
setdate_for_query: date_for_query
},
success: function(data) {
let graph_data_v10070 = data.arr_v10070;
let graph_labels = data.arr_date;
var ctx = document.getElementById("Option_Graph").getContext("2d");
window.myChart = new Chart(ctx, {
type: 'line',
data: {
labels: graph_labels,
datasets: [{
label: 'Energie in kwh',
data: graph_data_v10070,
borderColor: 'blue', // nur eine Farbe
borderWidth: 1,
pointRadius: 0,
spanGaps: false,
fill: false,
}]
},
options: {
animation: false,
responsive: true,
elements: {
line: {
tension: 0
}
},
tooltips: {
enabled: false
},
hover: {
mode: null
},
scales: {
xAxes: [{
display: true,
gridLines: {
display: false
},
ticks: {
autoSkip: false,
maxTicksLimit: 25
}
}],
yAxes: [{
display: true
}]
}
}
});
},
error: function(xhr, status, error) {
console.error("Fehler bei der AJAX-Anfrage:", error);
}
});
}
Aufbau der Datei get_10070_date.php
Diese Datei liefert alle historischen Leistungsdaten (OBIS 10.07.0) eines bestimmten Tages. Die Werte werden in regelmäßigen Abständen (z. B. jede Minute) ausgelesen und für die Tagesauswertung (Option 5) als JSON an das Liniendiagramm übergeben.
<?php
/* Datenbankverbindung */
include 'dbcon.php'; // Siehe SQL Verbindung oben
$date_for_query = $_GET['setdate_for_query'];
$statement = "SELECT obis_10070, TimeStamp
FROM obis_10070
WHERE TimeStamp like '$date_for_query%'
ORDER by TimeStamp";
$sqlresult = mysqli_query($dbcon, $statement);
// Arrays vorbereiten
$arr_v10070 = []; // Für Tageswerte aus obis 10070
$arr_date = []; // Für date
// Ergebnis durchlaufen und Werte in Arrays speichern
while ($row = mysqli_fetch_assoc($sqlresult)) {
$arr_v10070[] = $row['obis_10070'];
$dateObj = new DateTime($row['TimeStamp']);
$arr_date[] = $dateObj->format('H:i');
}
/* Verbindung zur SQL-DB trennen */
mysqli_close($dbcon);
// 1. Schritt: Werte auf nächste volle Stunde aufrunden (außer erster Wert bleibt unverändert)
for ($i = 0; $i < count($arr_date); $i++) {
// Erster Wert bleibt so, wie er ist
if ($i == 0) continue;
if ($arr_date[$i] === "") continue;
list($h, $m) = explode(":", $arr_date[$i]);
$h = (int)$h;
$m = (int)$m;
if ($m > 0) {
$h++;
if ($h == 24) $h = 0;
}
$arr_date[$i] = str_pad($h, 2, "0", STR_PAD_LEFT) . ":00";
}
// 2. Schritt: Nur letzten Eintrag pro voller Stunde behalten (ausgenommen erster und letzter Wert im Array)
$last_per_hour = [];
// Alle Stunden mit dem letzten Index merken (inklusive erster und letzter Werte, die wir später schützen)
for ($i = 0; $i < count($arr_date); $i++) {
if ($arr_date[$i] !== "") {
$last_per_hour[$arr_date[$i]] = $i;
}
}
// 3. Schritt: Werte entfernen, die nicht letzter Eintrag ihrer vollen Stunde sind, außer erste & letzte Position
for ($i = 0; $i < count($arr_date); $i++) {
if ($i == 0 || $i == count($arr_date) - 1) {
// Erster und letzter Wert bleiben erhalten, egal was
continue;
}
if ($arr_date[$i] !== "") {
// Wenn dieser Index nicht der letzte für diese Stunde ist → leer machen
if ($last_per_hour[$arr_date[$i]] !== $i) {
$arr_date[$i] = "";
}
}
}
// Die Arrays in ein assoziatives Array packen
$data = [
'arr_v10070' => $arr_v10070,
'arr_date' => $arr_date
];
// Setze den Content-Type auf JSON
header('Content-Type: application/json');
// Sende die Daten als JSON zurück
echo json_encode($data);
?>
