Zusammenlegung
- Die sechs Endpunkte getConsData_/getProdData_{month,year,decade}.php sind
ajax/energyHistory.php?series=&range= gewichen, der gemeinsame Aufbau der
Chart-Daten steht in ajax/chartData.php. Die erzeugte SQL wurde gegen alle
sechs Originale abgeglichen.
- Die 13 Raeume der Home-Ansicht stehen nur noch in restricted/rooms.php.
home.php rendert die SVG-Kacheln daraus, homeMQTT.js bekommt dieselbe
Tabelle als JSON (346 -> 222 bzw. 428 -> 197 Zeilen).
- Gemeinsame JS-Helfer in js/solar/common.js; geteilte Bausteine fuer
Wetterkacheln, Chart-Skripte und das Formular der Ladesteuerung.
- Seitenvorlagen sind jetzt .php und werden eingebunden, statt per
file_get_contents zusammengesetzt zu werden.
Fehlerbehebungen
- ?action=weather fuehrte auf eine leere Seite, es gibt jetzt weather.php.
- homeMQTT.js griff auf ein #meteogram zu, das home.php nie hatte, und brach
damit den readystatechange-Handler ab.
- Die Heizungsseite abonnierte weatherStation/#, zeigte die Werte aber nie an.
Ladelast
- Chart.js, MQTT und Meteogramm werden nur noch auf den Seiten geladen, die
sie brauchen; die Seitentabelle dafuer steht in index.php.
- mqtt.js durch die minifizierte Fassung ersetzt (859 -> 359 KB). MQTT.js
5.14.1, byte-identisch mit dem signierten npm-Tarball.
- Rund 3,1 MB ungenutzte Vendor-Reste und AdminLTE-Demobilder entfernt.
- Solar 1796 -> 1240 KB, Home 1796 -> 873 KB, Historie 1796 -> 843 KB.
Speicher im Browser
- Chart.defaults.devicePixelRatio auf 1.5 gedeckelt. Die Zeichenpuffer der
Diagramme waren mit 20-45 MB der groesste Posten der Seite.
- Das Meteogramm-iframe laedt erst beim Hinscrollen.
Realtime-SVG
- Filterbereiche auf das noetige Mass verkleinert und den wirkungslosen
feOffset-Durchgang entfernt: 60 % weniger gerasterte Filterflaeche bei
pixelgleichem Ergebnis.
- Die Fluss-Animation laeuft ueber transform statt stroke-dashoffset, mit
Punkten statt Strichmuster; sie ruht, wo kein Fluss anliegt.
- Der Wertupdate schreibt nur noch bei echter Aenderung und benutzt
textContent statt innerHTML: 9 statt 86 Elemente pro Update, davon keines
mit Filter. describeArc rundet auf volle Grad.
- waterInfo auf scale(0.90) wie die uebrigen Info-Gruppen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
194 lines
7.0 KiB
JavaScript
194 lines
7.0 KiB
JavaScript
var mqttData = {};
|
||
|
||
const solarMQTT = {
|
||
getMQTT: function () {
|
||
const id = Math.random().toString(36).substring(7);
|
||
const topic = "#";
|
||
const connection = "wss://mqtt.nas.el-wa.org:443"
|
||
mqttsolarTreeDone = false;
|
||
// const connection = "ws://username:password@37.97.203.138:8083" // Works
|
||
// const connection = "wss://public:public@public.cloud.shiftr.io" // Works
|
||
const client = mqtt.connect(connection, {
|
||
rejectUnauthorized: false,
|
||
});
|
||
|
||
client.on("message", messageReceived);
|
||
client.on("connect", function () {
|
||
client.subscribe("solarManager/#");
|
||
client.subscribe("wattpilot/properties/lmo/state");
|
||
client.subscribe("wattpilot/properties/ftt/state");
|
||
client.subscribe("wattpilot/properties/fte/state");
|
||
client.subscribe("wattpilot/properties/amp/state");
|
||
client.subscribe("wattpilot/properties/car/state");
|
||
client.subscribe("go-eCharger/270003/amp");
|
||
client.subscribe("go-eCharger/270003/ate");
|
||
client.subscribe("go-eCharger/270003/lmo");
|
||
client.subscribe("go-eCharger/270003/att");
|
||
client.subscribe("go-eCharger/270003/car");
|
||
client.subscribe("weatherStation/#");
|
||
});
|
||
client.on("error", function (error) {
|
||
//alert("MQTT Error: " + error);
|
||
});
|
||
client.on('end', function () {
|
||
setTimeout(getMQTT, 5000);
|
||
alert("MQTT Disconnected, try to reconnect in 5 secs.");
|
||
})
|
||
|
||
function getNestedProp(obj, path) {
|
||
return path.split('/').reduce((acc, key) => acc && acc[key], obj);
|
||
}
|
||
function setNestedProp(obj, path, value) {
|
||
var schema = obj; // a moving reference to internal objects within obj
|
||
var pList = path.split('/');
|
||
var len = pList.length;
|
||
for (var i = 0; i < len - 1; i++) {
|
||
var elem = pList[i];
|
||
if (!schema[elem]) schema[elem] = {}
|
||
schema = schema[elem];
|
||
}
|
||
|
||
schema[pList[len - 1]] = value;
|
||
}
|
||
|
||
function messageReceived(topic, message) {
|
||
setNestedProp(mqttData, topic, message);
|
||
if (topic == "solarManager/P_Load") {
|
||
setTimeout(function () { solarSVG.updateValuesMQTT(mqttData) }, 200); //give the object tree some time to build up and receive all values
|
||
} else if (topic == "weatherStation/windDeg") {
|
||
setTimeout(function () { updateWeatherCards(name => mqttData["weatherStation"]?.[name]) }, 200);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
const solarSVG = {
|
||
updateCnt: 99,
|
||
updateValuesMQTT: function (mqttData) {
|
||
if (this.updateCnt > 10) {
|
||
this.updateCnt = 0;
|
||
var obj = document.querySelector("object");
|
||
var htmlNode = obj.contentDocument;
|
||
htmlNode.getElementById("PufferOtxt").innerHTML = mqttData["solarManager"]["t_buffT"] + " °C";
|
||
htmlNode.getElementById("PufferMtxt").innerHTML = mqttData["solarManager"]["t_buffM"] + " °C";
|
||
htmlNode.getElementById("PufferUtxt").innerHTML = mqttData["solarManager"]["t_buffB"] + " °C";
|
||
htmlNode.getElementById("heaterVL").innerHTML = mqttData["solarManager"]["t_heatVL"] + " °C";
|
||
htmlNode.getElementById("heaterRL").innerHTML = mqttData["solarManager"]["t_heatRL"] + " °C";
|
||
htmlNode.getElementById("thermeVLfb").innerHTML = mqttData["solarManager"]["t_gasVLu"] + " °C";
|
||
htmlNode.getElementById("thermeVLww").innerHTML = mqttData["solarManager"]["t_gasVLo"] + " °C";
|
||
htmlNode.getElementById("thermeRL").innerHTML = mqttData["solarManager"]["t_gasRL"] + " °C";
|
||
htmlNode.getElementById("fbVL").innerHTML = mqttData["solarManager"]["t_fbVL"] + " °C";
|
||
htmlNode.getElementById("fbRL").innerHTML = mqttData["solarManager"]["t_fbRL"] + " °C";
|
||
htmlNode.getElementById("triac").innerHTML = mqttData["solarManager"]["t_triac"] + " °C";
|
||
}
|
||
this.updateCnt++;
|
||
}
|
||
|
||
}
|
||
|
||
var chartSettings = {
|
||
type: 'line',
|
||
options: {
|
||
animation: true,
|
||
plugins: {
|
||
annotation: {
|
||
common: { type: 'box', drawTime: 'beforeDatasetsDraw', yScaleID: 'y-axis-0', backgroundColor: 'rgba(255, 255, 255, 0.05)', init: true },
|
||
annotations: []
|
||
},
|
||
tooltip: {
|
||
position: 'nearest',
|
||
pointStyle: "circle",
|
||
boxWidth: 4,
|
||
usePointStyle: true,
|
||
callbacks: {
|
||
label: function (context) {
|
||
let label = context.dataset.label || '';
|
||
if (label) {
|
||
label += ': ';
|
||
}
|
||
if (context.dataset.yAxisID == "y1") {
|
||
label += Math.round(context.parsed.y * 10) / 10 + " " + "L/min";
|
||
} else {
|
||
if (context.parsed.y !== null) {
|
||
ret = scale(Math.round(context.parsed.y), false);
|
||
label += ret[0] + " " + ret[1] + "°C";
|
||
}
|
||
}
|
||
return label;
|
||
},
|
||
},
|
||
},
|
||
legend: {
|
||
position: "bottom",
|
||
labels: {
|
||
pointStyleWidth: 10,
|
||
usePointStyle: true,
|
||
pointStyle: "line",
|
||
}
|
||
},
|
||
},
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
interaction: {
|
||
intersect: false,
|
||
mode: 'index',
|
||
},
|
||
scales: {
|
||
x: {
|
||
adapters: {
|
||
date: {
|
||
locale: "DE-de"
|
||
}
|
||
},
|
||
ticks: {
|
||
|
||
},
|
||
type: 'timestack',
|
||
},
|
||
y: {
|
||
stacked: false,
|
||
display: true,
|
||
position: 'left',
|
||
ticks: {
|
||
callback: value => `${value} °C`,
|
||
},
|
||
title: {
|
||
display: true,
|
||
text: "Temperatur"
|
||
}
|
||
},
|
||
y1: {
|
||
stacked: false,
|
||
display: true,
|
||
position: 'right',
|
||
ticks: {
|
||
callback: value => `${value} L/min`,
|
||
},
|
||
title: {
|
||
display: true,
|
||
text: "Wasserverbrauch"
|
||
},
|
||
data:{}
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
var chartData = {};
|
||
const heatChart = new Chart(
|
||
document.querySelector('#heat-chart'),
|
||
Object.assign({}, chartSettings)
|
||
);
|
||
const waterChart = new Chart(
|
||
document.querySelector('#water-chart'),
|
||
Object.assign({}, chartSettings)
|
||
);
|
||
|
||
document.addEventListener('readystatechange', function () {
|
||
if (event.target.readyState === "complete") {
|
||
solarMQTT.getMQTT();
|
||
getData(heatChart, 'ajax/getHeaterData.php', { sunrise: { FROM: -24, TO: 0 } });
|
||
getData(waterChart, 'ajax/getWaterData.php', { sunrise: { FROM: -24, TO: 0 } });
|
||
}
|
||
});
|