Initial commit: Haussteuerung V2/V3 Web-Interface

This commit is contained in:
Thebille
2026-08-06 06:09:57 +02:00
commit 46c45518a3
46 changed files with 7285 additions and 0 deletions
+386
View File
@@ -0,0 +1,386 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>TTh</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<link href="form.css" rel="stylesheet" type="text/css" />
<style type="text/css">
.auto-style1 {
color: #FF0000;
font-family: "Arial";
}
.auto-style4 {
font-family: "Arial";
font-size: x-large;
text-align: left;
}
.auto-style5 {
font-family: "Arial";
font-size: x-large;
text-align: center;
}
.auto-style6 {
color: #000000;
font-size: xx-small;
}
.auto-style10 {
color: #FF0000;
font-family: "Arial";
font-size: 11px;
line-height: 1.15;
margin: 2px 0;
}
.sz-layout {
display: flex;
align-items: flex-start;
gap: 16px;
padding: 8px 0;
}
.sz-values {
min-width: 180px;
display: flex;
flex-direction: column;
gap: 2px;
}
.sz-chart-wrap {
min-width: 360px;
}
#powerChart {
width: 360px;
height: 180px;
display: block;
border-radius: 12px;
background: rgba(255,255,255,0.06);
border: 1px solid rgba(255,255,255,0.14);
}
</style>
</head>
<body style="color: #00FF00; background-color: #000000">
<div id="masthead">
</div>
<div id="top_nav">
</div>
<div id="container">
<div id="page_content">
<div class="sz-layout">
<div>
<p id="tacho_div"></p>
</div>
<div class="sz-values">
<p class="auto-style10" id="ergebnisx1"></p>
<p class="auto-style10" id="ergebnisx2"></p>
<p class="auto-style10" id="ergebnisx3"></p>
<p class="auto-style10" id="ergebnisx4"></p>
<p class="auto-style10" id="ergebnisx5"></p>
<p class="auto-style10" id="ergebnisx6"></p>
<p class="auto-style10" id="ergebnisx7"></p>
<p class="auto-style10" id="ergebnisx8"></p>
<p class="auto-style10" id="ergebnisx9"></p>
<p class="auto-style10" id="ergebnisx10"></p>
<p class="auto-style10" id="ergebnisx11"></p>
<p class="auto-style10" id="ergebnisx12"></p>
</div>
<div class="sz-chart-wrap">
<canvas id="powerChart" width="360" height="180"></canvas>
</div>
</div>
</div>
</div>
<div id="footer">
</div>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
let ergebnis = [];
let ergebnis_min = [];
let powerHistory = [];
// Chart aktuelle Leistung 20s
google.charts.load('current', { 'packages': ['corechart'] });
google.charts.setOnLoadCallback(drawChart_live);
function drawChart_live() {
var data = google.visualization.arrayToDataTable([
['Stunde', 'kWh'],
['0', parseInt(liveChart[1])],
['1', parseInt(liveChart[2])],
['2', parseInt(liveChart[3])],
['3', parseInt(liveChart[4])],
['4', parseInt(liveChart[5])],
['5', parseInt(liveChart[6])],
['6', parseInt(liveChart[7])],
['8', parseInt(liveChart[8])],
['9', parseInt(liveChart[9])],
['10', parseInt(liveChart[10])],
['11', parseInt(liveChart[11])],
['12', parseInt(liveChart[12])],
['13', parseInt(liveChart[13])],
['14', parseInt(liveChart[14])],
['15', parseInt(liveChart[15])],
['16', parseInt(liveChart[16])],
['17', parseInt(liveChart[17])],
['18', parseInt(liveChart[18])],
['19', parseInt(liveChart[19])],
['20', parseInt(liveChart[20])]
]);
var options = {
title: 'Verlauf [s]',
backgroundColor: 'black',
chartArea: { left: 40, top: 0, width: '100%', height: '90%' },
//SvAxis: {maxValue: 8000, minValue: -8000},
curveType: 'function',
legend: { position: 'none' }
};
var chart_live = new google.visualization.LineChart(document.getElementById('curve_chart'));
chart_live.draw(data, options);
}
function addPowerSample(value) {
var now = Date.now();
if (!isFinite(value)) return;
// store a point on every value update (each successful poll)
powerHistory.push({ t: now, v: value });
var cutoff = now - (5 * 60 * 1000); // 5 minutes
while (powerHistory.length && powerHistory[0].t < cutoff) {
powerHistory.shift();
}
}
function drawPowerChart() {
var canvas = document.getElementById('powerChart');
if (!canvas) return;
var ctx = canvas.getContext('2d');
var w = canvas.width, h = canvas.height;
// background
ctx.clearRect(0, 0, w, h);
ctx.fillStyle = 'rgba(0,0,0,0.35)';
ctx.fillRect(0, 0, w, h);
// no data yet
if (!powerHistory.length) {
ctx.fillStyle = 'rgba(234,240,255,0.75)';
ctx.font = '12px Segoe UI, Arial, sans-serif';
ctx.fillText('Leistung (letzte 5 min) warte auf Daten…', 12, 24);
return;
}
var minV = powerHistory[0].v, maxV = powerHistory[0].v;
for (var i = 1; i < powerHistory.length; i++) {
var v = powerHistory[i].v;
if (v < minV) minV = v;
if (v > maxV) maxV = v;
}
if (minV === maxV) { minV -= 1; maxV += 1; }
var padL = 38, padR = 10, padT = 18, padB = 22;
var plotW = w - padL - padR;
var plotH = h - padT - padB;
var t0 = powerHistory[0].t;
var t1 = powerHistory[powerHistory.length - 1].t;
if (t0 === t1) { t0 -= 1; t1 += 1; }
// grid
ctx.strokeStyle = 'rgba(255,255,255,0.10)';
ctx.lineWidth = 1;
for (var gy = 0; gy <= 4; gy++) {
var y = padT + (plotH * gy / 4);
ctx.beginPath();
ctx.moveTo(padL, y);
ctx.lineTo(padL + plotW, y);
ctx.stroke();
}
// labels
ctx.fillStyle = 'rgba(234,240,255,0.75)';
ctx.font = '12px Segoe UI, Arial, sans-serif';
ctx.fillText('Leistung letzte 5 min', 12, 14);
ctx.fillStyle = 'rgba(234,240,255,0.65)';
ctx.font = '11px Segoe UI, Arial, sans-serif';
ctx.fillText(Math.round(maxV) + ' W', 6, padT + 10);
ctx.fillText(Math.round(minV) + ' W', 6, padT + plotH);
// line
ctx.strokeStyle = 'rgba(99,212,255,0.95)';
ctx.lineWidth = 2;
ctx.beginPath();
for (var j = 0; j < powerHistory.length; j++) {
var p = powerHistory[j];
var x = padL + ((p.t - t0) / (t1 - t0)) * plotW;
var yv = padT + (1 - ((p.v - minV) / (maxV - minV))) * plotH;
if (j === 0) ctx.moveTo(x, yv); else ctx.lineTo(x, yv);
}
ctx.stroke();
// last point
var last = powerHistory[powerHistory.length - 1];
var lx = padL + ((last.t - t0) / (t1 - t0)) * plotW;
var ly = padT + (1 - ((last.v - minV) / (maxV - minV))) * plotH;
ctx.fillStyle = 'rgba(124,255,178,0.95)';
ctx.beginPath();
ctx.arc(lx, ly, 3, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = 'rgba(234,240,255,0.85)';
ctx.font = '12px Segoe UI, Arial, sans-serif';
ctx.fillText(Math.round(last.v) + ' W', w - 86, 14);
}
// Minuten
function drawChart_Minuten() {
let array_min = [];
for (i = 0; i <= 59; i++) {
if (parseFloat(ergebnis_min[i]) > 0) {
array_min[i, parseFloat(ergebnis_min[i])];
} else {
break;
};
}
var data = google.visualization.arrayToDataTable([array_min]);
var options = {
title: 'Tag',
titleTextStyle: { color: 'red' },
backgroundColor: 'black',
chartArea: { left: 40, top: 20, width: '100%', height: '90%' },
hAxis: { maxValue: 59, minValue: 0, titleTextStyle: { color: 'red' }, textStyle: { color: 'red' } },
vAxis: { title: 'kWh', titleTextStyle: { color: 'red' }, textStyle: { color: 'red' } },
legend: 'none',
trendlines: { 0: { type: 'linear', color: 'red' } },
};
var chart_Minute = new google.visualization.ScatterChart(document.getElementById('chart_div_Minute'));
chart_Minute.draw(data, options);
}
// Tacho
google.charts.load('current', { 'packages': ['gauge'] });
google.charts.setOnLoadCallback(drawTacho);
function drawTacho() {
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
['Leistung', 50]
]);
var options = {
width: 200, height: 200,
max: 8000, min: -8000,
greenFrom: -9000, greenTo: 0,
redFrom: 5000, redTo: 9000,
yellowFrom: 0, yellowTo: 1000,
minorTicks: 5
};
var tacho = new google.visualization.Gauge(document.getElementById("tacho_div"));
tacho.draw(data, options);
setInterval(function () {
data.setValue(0, 1, parseInt(ergebnis[3]));
tacho.draw(data, options);
//dia_leistung();
}, 1000);
}
function showDataTable() {
var xmlhttp;
if (window.XMLHttpRequest) {
// code fuer IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {
// code fuer IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET", "stromzaehler_state.html", true);
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var outputArea = document.getElementById("OutputArea");
if (outputArea) outputArea.innerHTML = xmlhttp.responseText;
// Refresh Timeout zum Neuladen der Daten setzen
for (i = 1; i <= 12; i++) {
var node = document.getElementById('stromx' + i);
ergebnis[i] = node ? node.innerText : '';
}
var p = parseFloat(ergebnis[3]);
addPowerSample(p);
drawPowerChart();
document.getElementById('ergebnisx1').innerHTML = 'Bezug: ' + ergebnis[1] + ' kWh';
document.getElementById('ergebnisx2').innerHTML = 'Einspeisung: ' + ergebnis[2] + ' kWh';
document.getElementById('ergebnisx3').innerHTML = 'aktuelle Leistung: ' + ergebnis[3] + ' W';
document.getElementById('ergebnisx4').innerHTML = 'täglicher Bezug: ' + ergebnis[4] + ' kWh';
var diff1 = parseFloat(ergebnis[1]) - parseFloat(ergebnis[5]);
var diff2 = parseFloat(ergebnis[5]) - parseFloat(ergebnis[6]);
var diff3 = parseFloat(ergebnis[6]) - parseFloat(ergebnis[7]);
var diff4 = parseFloat(ergebnis[7]) - parseFloat(ergebnis[8]);
var diff5 = parseFloat(ergebnis[8]) - parseFloat(ergebnis[9]);
var diff6 = parseFloat(ergebnis[9]) - parseFloat(ergebnis[10]);
var diff7 = parseFloat(ergebnis[10]) - parseFloat(ergebnis[11]);
var diff8 = parseFloat(ergebnis[11]) - parseFloat(ergebnis[12]);
document.getElementById('ergebnisx5').innerHTML = '-1: ' + (isNaN(diff1) ? '-' : diff1.toFixed(2)) + ' kWh';
document.getElementById('ergebnisx6').innerHTML = '-2: ' + (isNaN(diff2) ? '-' : diff2.toFixed(2)) + ' kWh';
document.getElementById('ergebnisx7').innerHTML = '-3: ' + (isNaN(diff3) ? '-' : diff3.toFixed(2)) + ' kWh';
document.getElementById('ergebnisx8').innerHTML = '-4: ' + (isNaN(diff4) ? '-' : diff4.toFixed(2)) + ' kWh';
document.getElementById('ergebnisx9').innerHTML = '-5: ' + (isNaN(diff5) ? '-' : diff5.toFixed(2)) + ' kWh';
document.getElementById('ergebnisx10').innerHTML = '-6: ' + (isNaN(diff6) ? '-' : diff6.toFixed(2)) + ' kWh';
document.getElementById('ergebnisx11').innerHTML = '-7: ' + (isNaN(diff7) ? '-' : diff7.toFixed(2)) + ' kWh';
document.getElementById('ergebnisx12').innerHTML = '-8: ' + (isNaN(diff8) ? '-' : diff8.toFixed(2)) + ' kWh';
setTimeout(refreshOutputArea, 500);
}
}
xmlhttp.send(null);
}
function refreshOutputArea() {
showDataTable();
}
window.onload = function () {
refreshOutputArea();
}
</script>
</div>
<div id="OutputArea" style="position:fixed;clip:rect(0,0,0,0);overflow:hidden;"></div>
</body>
</html>