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) { 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 () { updateValuesWeather() }, 200); //give the object tree some time to build up and receive all values } } } } const solarSVG = { updateCnt: 99, fillElementArray: function () { }, updateValuesMQTT: function (mqttData) { const angleFactor = 15000 / 288; const sixkWangleFactor = 6000 / 288; var cons = Number(mqttData["solarManager/P_Load"]); var pvn = JSON.parse(mqttData["solarManager/P_PVn"]); var pv = Number(mqttData["solarManager/P_PV"]); var pv2 = Number(pvn[1]); var pv1 = Number(pvn[0]); var pv3 = pv - (pv1 + pv2); var pbatt = Number(mqttData["solarManager/P_Akku"]); var limbatt = Number(mqttData["solarManager/crgMaxPct"]); var grid = Number(mqttData["solarManager/P_Grid"]); var soc = Number(mqttData["solarManager/SOC"]); var og = Number(mqttData["solarManager/og"]); var eg = Number(mqttData["solarManager/eg"]); var ug = Number(mqttData["solarManager/ug"]); var evsoc = Number(mqttData["solarManager/evSOC"]); var evlock = Number(mqttData["solarManager/evLock"]); var evMode = mqttData["solarManager/evMode"]; var evPower = Number(mqttData["solarManager/evPower"]); var plugev = Number(mqttData["solarManager/evPlug"]); var fuelev = Number(mqttData["solarManager/evFuel"]); var heatOG = Number(mqttData["solarManager/heatOG"]); var heatEG = Number(mqttData["solarManager/heatEG"]); var puffO = Number(mqttData["solarManager/t_buffT"]); var puffM = Number(mqttData["solarManager/t_buffM"]); var puffU = Number(mqttData["solarManager/t_buffB"]); var heatMode = mqttData["solarManager/heatMode"]; var carRemChrg = Number(mqttData["solarManager/carRemChrg"]); var aut = Number(mqttData["solarManager/autarky"]); var Pheat = Number(mqttData["solarManager/pHeat"]); var waterHeight = Number(mqttData["solarManager/waterHeight"]); var waterTemp = Number(mqttData["solarManager/waterTemp"]); var p_wr = Number(mqttData["solarManager/P_WR"]); var eff = Number(mqttData["solarManager/eff"]); var i_l1evu = Number(mqttData["solarManager/i_l1evu"]); var i_l2evu = Number(mqttData["solarManager/i_l2evu"]); var i_l3evu = Number(mqttData["solarManager/i_l3evu"]); var evPowerOG = Number(mqttData["solarManager/evPowerOG"]); var evPlugOG = Number(mqttData["solarManager/evPlugOG"]); var evModeOG = mqttData["solarManager/evModeOG"]; var common = -cons - ug - eg + og ; if(common < 0){ common = 0; } var htmlNode = document htmlNode.getElementById('consumerArc').setAttribute("d", describeArc(100, 100, 95, 0, Math.round(-cons / angleFactor))); htmlNode.getElementById("ogArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(-og / angleFactor))); htmlNode.getElementById("consumerText").innerHTML = powerToString(-cons); htmlNode.getElementById("consumerTextAllg").innerHTML = "Gemein: "+powerToString(common); if (evPower > 0) { htmlNode.getElementById("evCharge").style.display = ""; if (carRemChrg > -1) { var today = new Date(); today.setMinutes(today.getMinutes() + carRemChrg); var h = today.getHours(); var m = today.getMinutes(); if (h < 10) h = "0" + h; if (m < 10) m = "0" + m; htmlNode.getElementById("evRemText").innerHTML = h + ":" + m } } else { htmlNode.getElementById("evRemText").innerHTML = ""; } htmlNode.getElementById("ogText").innerHTML = powerToString(-og); htmlNode.getElementById("egText").innerHTML = powerToString(eg); htmlNode.getElementById("ugText").innerHTML = powerToString(ug); htmlNode.getElementById("pvText").innerHTML = powerToString(pv); htmlNode.getElementById("pv1txt").innerHTML = powerToString(pv1); htmlNode.getElementById("pv2txt").innerHTML = powerToString(pv2); htmlNode.getElementById("pv3txt").innerHTML = powerToString(pv3); htmlNode.getElementById("il1txt").innerHTML = Math.round(i_l1evu * 10) / 10 + " A" htmlNode.getElementById("il2txt").innerHTML = Math.round(i_l2evu * 10) / 10 + " A" htmlNode.getElementById("il3txt").innerHTML = Math.round(i_l3evu * 10) / 10 + " A" htmlNode.getElementById("batText").innerHTML = powerToString(pbatt); htmlNode.getElementById("heatText").innerHTML = powerToString(Pheat); htmlNode.getElementById("evText").innerHTML = powerToString(evPower * 1000); htmlNode.getElementById("evTextOG").innerHTML = powerToString(evPowerOG * 1000); htmlNode.getElementById("genText").innerHTML = "Autarkie: " + Math.round(aut) + " %"; htmlNode.getElementById("genInfoText").innerHTML = "Wirkungsgrad: " + Math.round(eff) + " %";// powerToString(p_wr); htmlNode.getElementById("gridText").innerHTML = powerToString(grid); htmlNode.getElementById("waterText").innerHTML = Math.round(waterHeight) / 10 + " cm" htmlNode.getElementById("waterTemp").innerHTML = (waterTemp).toPrecision(3) + " °C" htmlNode.getElementById("waterState").setAttribute("y", (100 - (waterHeight / 1500) * 100) + "%"); for (i = 0; i < pvn.length; i++) { htmlNode.getElementById("det_pv" + i + "P").innerHTML = powerToString(pvn[i]); } tttext = "" var i = 0; while (mqttData["solarManager/inverters" + i]) { if (mqttData["solarManager/inverters" + i+"/error"] > 0) { tttext = tttext + '' + mqttData["solarManager/inverters" + i+"/name"] + ":" tttext = tttext + '' + "--" + " °C" tttext = tttext + '' + "-- W" + "" } else { tttext = tttext + '' + mqttData["solarManager/inverters" + i+"/name"] + ":" tttext = tttext + '' + Math.round(mqttData["solarManager/inverters" + i+"/temp"]) + " °C" tttext = tttext + '' + powerToString(mqttData["solarManager/inverters" + i+"/p_AC"]) + "" } i++; } htmlNode.getElementById("invList").innerHTML = tttext htmlNode.getElementById("egArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(eg / angleFactor))); htmlNode.getElementById("ugArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(ug / angleFactor))); htmlNode.getElementById("pvArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(pv1 / angleFactor))); htmlNode.getElementById("pv2Arc").setAttribute("d", describeArc(100, 100, 95, Math.round(pv1 / angleFactor), Math.round(pv1 / angleFactor) + Math.round(pv2 / angleFactor))); htmlNode.getElementById("pv3Arc").setAttribute("d", describeArc(100, 100, 95, Math.round(pv1 / angleFactor) + Math.round(pv2 / angleFactor), Math.round(pv1 / angleFactor) + Math.round(pv2 / angleFactor) + Math.round(pv3 / angleFactor))); if (pbatt < 0) { if (limbatt < 100) { htmlNode.getElementById("charge").style.display = "none"; htmlNode.getElementById("batLim").style.display = ""; htmlNode.getElementById("batLimText").innerHTML = Math.round(limbatt) + "%"; } else { htmlNode.getElementById("charge").style.display = ""; htmlNode.getElementById("batLim").style.display = "none"; } htmlNode.getElementById("batArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(-pbatt / angleFactor))); htmlNode.getElementById("battani").setAttribute("class", "stream-rev"); htmlNode.getElementById("battani").setAttribute("stroke-width", 55 * (1 - Math.exp(pbatt / 2000))); } else { htmlNode.getElementById("charge").style.display = "none"; htmlNode.getElementById("batLim").style.display = "none"; htmlNode.getElementById("batArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(pbatt / angleFactor))); htmlNode.getElementById("battani").setAttribute("class", "stream"); htmlNode.getElementById("battani").setAttribute("stroke-width", 55 * (1 - Math.exp(-pbatt / 2000))); } htmlNode.getElementById("batChargeState").setAttribute("y", (100 - soc) + "%"); //htmlNode.getElementById("heatChargeState").setAttribute("y", 100 - ((((puffO + puffM) / 2) - 30) * 1.66) + "%"); htmlNode.getElementById('tmpH').setAttribute("stop-color", assignColor("#2389BA", "#BA3B23", 20, 80, puffO)); htmlNode.getElementById('tmpM').setAttribute("stop-color", assignColor("#2389BA", "#BA3B23", 20, 80, puffM)); htmlNode.getElementById('tmpL').setAttribute("stop-color", assignColor("#2389BA", "#BA3B23", 20, 80, puffU)); htmlNode.getElementById("batSOC").innerHTML = soc + " %"; htmlNode.getElementById("evArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(evPower * 2000 / angleFactor))); htmlNode.getElementById("evChargeState").setAttribute("y", (100 - evsoc) + "%"); htmlNode.getElementById("evSOC").innerHTML = evsoc + " %"; htmlNode.getElementById("evFuel").innerHTML = fuelev + " %"; htmlNode.getElementById("heatArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(Pheat / sixkWangleFactor))); htmlNode.getElementById("heatUp").innerHTML = Math.round(puffO * 10) / 10 + " °C"; htmlNode.getElementById("heatDown").innerHTML = Math.round(puffM * 10) / 10 + " °C"; if (evlock == false) { htmlNode.getElementById("evLock").style.display = "none"; } else { htmlNode.getElementById("evLock").style.display = ""; } if (heatMode == "eco") { htmlNode.getElementById("heatEco").style.display = ""; htmlNode.getElementById("heatDefault").style.display = "none"; } else { htmlNode.getElementById("heatEco").style.display = "none"; htmlNode.getElementById("heatDefault").style.display = ""; } if (evMode == "Eco") { htmlNode.getElementById("evEco").style.display = ""; htmlNode.getElementById("evNextTrip").style.display = "none"; htmlNode.getElementById("evDefault").style.display = "none"; } else if (evMode == "Next Trip") { htmlNode.getElementById("evEco").style.display = "none"; htmlNode.getElementById("evNextTrip").style.display = ""; htmlNode.getElementById("evDefault").style.display = "none"; } else { htmlNode.getElementById("evEco").style.display = "none"; htmlNode.getElementById("evNextTrip").style.display = "none"; htmlNode.getElementById("evDefault").style.display = ""; } if (heatOG) { htmlNode.getElementById("heatOG").style.display = ""; } else { htmlNode.getElementById("heatOG").style.display = "none"; } if (heatEG) { htmlNode.getElementById("heatEG").style.display = ""; } else { htmlNode.getElementById("heatEG").style.display = "none"; } if (plugev != "no car") { htmlNode.getElementById("evPlug").style.display = ""; } else { htmlNode.getElementById("evPlug").style.display = "none"; } if (evModeOG == "Eco") { htmlNode.getElementById("evEcoOG").style.display = ""; htmlNode.getElementById("evNextTripOG").style.display = "none"; htmlNode.getElementById("evDefaultOG").style.display = "none"; } else if (evModeOG == "Next Trip") { htmlNode.getElementById("evEcoOG").style.display = "none"; htmlNode.getElementById("evNextTripOG").style.display = ""; htmlNode.getElementById("evDefaultOG").style.display = "none"; } else { htmlNode.getElementById("evEcoOG").style.display = "none"; htmlNode.getElementById("evNextTripOG").style.display = "none"; htmlNode.getElementById("evDefaultOG").style.display = ""; } if (evPlugOG > 0) { htmlNode.getElementById("evPlugOG").style.display = ""; } else { htmlNode.getElementById("evPlugOG").style.display = "none"; } if (grid < 0) { htmlNode.getElementById("gridArc").setAttribute("d", describeArc(100, 100, 95, 0, -grid / angleFactor)); htmlNode.getElementById("consGridani").setAttribute("class", "stream-rev"); htmlNode.getElementById("consGridani").setAttribute("stroke-width", 55 * (1 - Math.exp(grid / 2000))); } else { htmlNode.getElementById("gridArc").setAttribute("d", describeArc(100, 100, 95, 0, grid / angleFactor)); htmlNode.getElementById("consGridani").setAttribute("class", "stream"); htmlNode.getElementById("consGridani").setAttribute("stroke-width", 55 * (1 - Math.exp(-grid / 2000))); } htmlNode.getElementById("consEVani").setAttribute("stroke-width", 55 * (1 - Math.exp(-evPower))); htmlNode.getElementById("consEVOGani").setAttribute("stroke-width", 55 * (1 - Math.exp(-evPowerOG))); htmlNode.getElementById("consOGani").setAttribute("stroke-width", 55 * (1 - Math.exp(og / 2000))); htmlNode.getElementById("consUGani").setAttribute("stroke-width", 55 * (1 - Math.exp( -ug / 2000))); htmlNode.getElementById("consHeatAni").setAttribute("stroke-width", 55 * (1 - Math.exp(-Pheat / 2000))); htmlNode.getElementById("consAni").setAttribute("stroke-width", 55 * (1 - Math.exp(cons / 2000))); htmlNode.getElementById("consEGani").setAttribute("stroke-width", 55 * (1 - Math.exp(-eg / 2000))); htmlNode.getElementById("pvani").setAttribute("stroke-width", 55 * (1 - Math.exp(-pv / 2000))); htmlNode.getElementById("pvani"); } } 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: { footer: function (tooltipItems){return ""}, }, }, 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: true, display: true, min: 0, position: 'left', ticks: { callback: value => `${value / 1000} kW`, }, /*title: { display: true, text: "Leistung" }*/ }, y1: { stacked: false, display: true, position: 'right', min: 0, max: 100, ticks: { callback: value => `${value} %`, }, /*title: { display: true, text: "Ladestand" },*/ data:{} } } } }; var forecastChartSettings = { type: 'bar', options: { animation: true, plugins: { tooltip: { position: 'nearest', pointStyle: "circle", boxWidth: 4, usePointStyle: true, callbacks: { footer: function (tooltipItems){return ""}, }, }, 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', timestack:{ right_floating_tick_thres: 0.3, format_style: {month: 'long'}, } }, y: { stacked: false, display: true, position: 'left', ticks: { callback: value => `${value / 1000} kW`, }, /*title: { display: true, text: "Leistung" }*/ }, } } }; var modalEV = new bootstrap.Modal(document.getElementById('modalEV'), { keyboard: false }); var chartData = {}; var mqttData = {}; var timeFrom = -24; var timeTo = 12; const consChart = new Chart( document.querySelector('#consumption-chart'), Object.assign({}, chartSettings) ); const prodChart = new Chart( document.querySelector('#production-chart'), Object.assign({}, chartSettings) ); const foreChart = new Chart( document.querySelector('#forecast-chart'), Object.assign({}, forecastChartSettings) ); function updateCharts(){ getData(consChart, 'ajax/getConsData.php',true,false,false); getData(prodChart, 'ajax/getProdData.php',true,false,false); } function prevDay(){ timeFrom -= 24; timeTo -= 24; var now = new Date(); now.setDate(now.getDate()+1+(timeFrom/24)); var day = ("0" + now.getDate()).slice(-2); var month = ("0" + (now.getMonth() + 1)).slice(-2); var selected = now.getFullYear()+"-"+(month)+"-"+(day); document.getElementById("DatePickerCons").value = selected; document.getElementById("DatePickerProd").value = selected; updateCharts(); } function changeDay(e){ const date1 = new Date(e.target.value); const date2 = new Date(); const difference = Math.floor((date1.getTime() - date2.getTime()) / (1000*60*60*24)) *24; timeFrom = difference; timeTo = difference+36; updateCharts(); //.then((ret) => enableEvents()); } function nextDay(){ timeFrom += 24; timeTo += 24; var now = new Date(); now.setDate(now.getDate()+1+(timeFrom/24)); var day = ("0" + now.getDate()).slice(-2); var month = ("0" + (now.getMonth() + 1)).slice(-2); var selected = now.getFullYear()+"-"+(month)+"-"+(day); document.getElementById("DatePickerCons").value = selected; document.getElementById("DatePickerProd").value = selected; updateCharts(); } document.addEventListener('readystatechange', function () { if (event.target.readyState === "complete") { solarMQTT.getMQTT(); getData(consChart, 'ajax/getConsData.php'); getData(prodChart, 'ajax/getProdData.php'); getData(foreChart,'ajax/getForecastData.php', false); getStats("Stats-Year","ajax/getStats.php?type=ThisYear"); solarSVG.fillElementArray(); this.getElementById("meteogram").innerHTML = ""; } }); String.prototype.toHHMM = function () { var sec_num = parseInt(this, 10); // don't forget the second param var hours = Math.floor(sec_num / 3600); var minutes = Math.floor((sec_num - (hours * 3600)) / 60); //var seconds = sec_num - (hours * 3600) - (minutes * 60); if (hours < 10) { hours = "0" + hours; } if (minutes < 10) { minutes = "0" + minutes; } return hours + ':' + minutes; } function loadingHTML(msg) { return "
Loading...
   " + msg + "
" } function openModal(type) { switch(type){ case "CarEG": document.getElementById("modal-title").innerHTML = "Autoladung EG"; contentURL = "ajax/carEG.php"; break; case "CarOG": document.getElementById("modal-title").innerHTML = "Autoladung OG"; contentURL = "ajax/carOG.php"; break; case "heater": document.getElementById("modal-title").innerHTML = "Steuerung Heizstab"; contentURL = "ajax/heater.php"; break; default: document.getElementById("modal-title").innerHTML = "Fehler"; contentURL = ""; break; } modalBodyElement = document.getElementById('modal-body'); modalBodyElement.innerHTML = loadingHTML("Wird geladen..."); document.getElementById("modalSaveBtn").addEventListener("click", submitFormAjax); document.getElementById("modalSaveBtn").contentURL = contentURL; modalEV.show(); fetch(contentURL, { method: 'GET', headers: { 'X-Requested-From-Modal': 'a', 'Requested-With-Ajax': 'ajax' } }) .then(response => response.text()) .then(html => { modalBodyElement.innerHTML = html; var slider = document.getElementById("modal-slider"); var span = document.getElementById("modal-slider-label"); switch(type){ case "CarEG": slider.oninput = function () { marginValue = parseInt(this.value); slider.style.setProperty("--background-size", `${marginValue}%`); if (marginValue < 10) { marginValue = marginValue - 0.4 * marginValue; } else if (marginValue < 85) { marginValue = marginValue - 4; } else { marginValue = marginValue - 4 - 0.5 * (marginValue - 85); } span.setAttribute('style', 'margin-left:' + marginValue + '%;'); span.innerHTML = this.value + "%"; } document.getElementById("evStart/Stop").addEventListener("click", submitFormAjax); document.getElementById("evStart/Stop").contentURL = contentURL; mode = new TextDecoder().decode(mqttData["wattpilot/properties/lmo/state"]); time = String(mqttData["wattpilot/properties/ftt/state"]); energy = mqttData["wattpilot/properties/fte/state"]; amp = new TextDecoder().decode(mqttData["wattpilot/properties/amp/state"]); car = new TextDecoder().decode(mqttData["wattpilot/properties/car/state"]); charge = Number(mqttData["solarManager/p_l1ev"])+Number(mqttData["solarManager/p_l2ev"])+Number(mqttData["solarManager/p_l3ev"]) if (charge < 0.2) { document.getElementById("evStart/Stop").innerHTML = 'Laden starten' } else { document.getElementById("evStart/Stop").innerHTML = 'Laden stoppen' } if (mode == "Awattar") { document.getElementById("EV_Eco").click(); } else if (mode == "Default") { document.getElementById("EV_Default").click(); } else if (mode == "AutomaticStop") { document.getElementById("EV_NextTrip").click(); } else { alert(mode); } document.getElementById("EV_NextTripTime").value = time.toHHMM(); document.getElementById("modal-slider").value = Math.round(energy * 100 / 14000); document.getElementById("modal-slider").dispatchEvent(new Event('input')); if (amp == "16") { document.getElementById("EV_16A").click(); } else if (amp == "10") { document.getElementById("EV_10A").click(); } else if (amp == "6") { document.getElementById("EV_6A").click(); } break; case "CarOG": slider.oninput = function () { marginValue = parseInt((this.value-this.min)*100/this.max); slider.style.setProperty("--background-size", `${marginValue}%`); if (marginValue < 10) { marginValue = marginValue - 0.4 * marginValue; } else if (marginValue < 85) { marginValue = marginValue - 4; } else { marginValue = marginValue - 4 - 0.5 * (marginValue - 85); } span.setAttribute('style', 'margin-left:' + marginValue + '%;'); span.innerHTML = this.value + "%"; } document.getElementById("evStart/Stop").addEventListener("click", submitFormAjax); document.getElementById("evStart/Stop").contentURL = contentURL; mode = mqttData["go-eCharger/270003/lmo"]; time = String(mqttData["go-eCharger/270003/att"]); energy = mqttData["go-eCharger/270003/ate"]; amp = mqttData["go-eCharger/270003/amp"]; car = mqttData["go-eCharger/270003/car"]; if (car != "2") { document.getElementById("evStart/Stop").innerHTML = 'Laden starten' } else { document.getElementById("evStart/Stop").innerHTML = 'Laden stoppen' } if (mode == "4") { document.getElementById("EV_Eco").click(); } else if (mode == "3") { document.getElementById("EV_Default").click(); } else if (mode == "5") { document.getElementById("EV_NextTrip").click(); } else { alert(mode); } document.getElementById("EV_NextTripTime").value = time.toHHMM(); document.getElementById("modal-slider").value = Math.round(energy * 100 / 14000); document.getElementById("modal-slider").dispatchEvent(new Event('input')); if (amp == "16") { document.getElementById("EV_16A").click(); } else if (amp == "10") { document.getElementById("EV_10A").click(); } else if (amp == "6") { document.getElementById("EV_6A").click(); } break; case "heater": slider.oninput = function () { marginValue = parseInt((this.value-this.min)*100/this.max); slider.style.setProperty("--background-size", `${marginValue}%`); if (marginValue < 10) { marginValue = marginValue - 0.4 * marginValue; } else if (marginValue < 85) { marginValue = marginValue - 4; } else { marginValue = marginValue - 4 - 0.5 * (marginValue - 85); } span.setAttribute('style', 'margin-left:' + marginValue + '%;'); if(this.value == 0){ span.innerHTML = "Automatik"; }else{ span.innerHTML = (this.value/10) + " kW"; } } if(mqttData["solarManager/heatMode"] == "eco"){ document.getElementById("modal-slider").value = 0; }else{ document.getElementById("modal-slider").value = Math.round(mqttData["solarManager/pHeat"]/100); } document.getElementById("modal-slider").dispatchEvent(new Event('input')); break; } }) .catch(error => { modalBodyElement.innerHTML = error.message; }); } function submitFormAjax(event) { let xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"); xmlhttp.onreadystatechange = function () { if (this.readyState === 4 && this.status === 200) modalEV.hide(); } const form = document.getElementById('modalEV').querySelector('form'); post = ""; // ✅ Get interesting form elements if (event.currentTarget.id == "evStart/Stop") { post = "evStart/Stop=" + event.currentTarget.innerHTML; } else { const formElements = Array.from(form.elements); for (let i = 0; i < formElements.length; i++) { if(formElements[i].name){ if (formElements[i].type == "radio" && formElements[i].checked) { post += formElements[i].name + "=" + encodeURIComponent(formElements[i].value) + "&"; } else if(formElements[i].type == "checkbox" && formElements[i].checked){ post += formElements[i].name + "=" + encodeURIComponent(formElements[i].value) + "&"; } else if(formElements[i].type == "button" && !formElements[i].classList.contains("accordion-button")){ post += formElements[i].name + "=" + encodeURIComponent(formElements[i].innerHTML) + "&"; }else if(formElements[i].type != "checkbox" && formElements[i].type != "radio") { post += formElements[i].name + "=" + encodeURIComponent(formElements[i].value) + "&"; } } } } xmlhttp.open("POST", event.currentTarget.contentURL, true); xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); document.getElementById('modalEV').querySelector('.modal-body').innerHTML = loadingHTML("Änderungen werden übernommen..."); xmlhttp.send(post); return false; } async function getData(chrt, url, sunrise=true, autoUpdate=true, animation=true) { try { chrt.options.events = []; console.log("fetching "+url+"?FROM="+timeFrom+"&TO="+timeTo); const response = await fetch(url+"?FROM="+timeFrom+"&TO="+timeTo); if (!response.ok) { console.log("err"); throw new Error(`Response status: ${response.status}`); } chrt.data = await response.json(); if(sunrise){ const response2 = await fetch("ajax/getSunrise.php?FROM="+timeFrom+"&TO="+timeTo); if (!response2.ok) { console.log("err"); throw new Error(`Response status: ${response2.status}`); } chrt.options.plugins.annotation.annotations = await response2.json(); } chrt.options.events = ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove']; if(animation) chrt.update(); else chrt.update("none"); } catch (error) { console.log(error.message); } if(autoUpdate){ setTimeout(function () { getData(chrt, url, sunrise,autoUpdate,animation) }, 5 * 60 * 1000); //renew data every 5 min. } } async function getDataOnly(chart, url, sunrise=true, autoUpdate=true, animation=true) { try { console.log("fetching "+url+"?FROM="+timeFrom+"&TO="+timeTo); const response = await fetch(url+"?FROM="+timeFrom+"&TO="+timeTo); if (!response.ok) { console.log("err"); throw new Error(`Response status: ${response.status}`); } chart.data = await response.json(); if(sunrise){ const response2 = await fetch("ajax/getSunrise.php?FROM="+timeFrom+"&TO="+timeTo); if (!response2.ok) { console.log("err"); throw new Error(`Response status: ${response2.status}`); } chart.options.plugins.annotation.annotations = await response2.json(); } } catch (error) { console.log(error.message); } if(autoUpdate){ setTimeout(function () { getData(chart, url, sunrise,autoUpdate,animation) }, 5 * 60 * 1000); //renew data every 5 min. } } async function getStats(elem_id, url) { try { console.log("fetching"); const response = await fetch(url); if (!response.ok) { console.log("err"); throw new Error(`Response status: ${response.status}`); } document.getElementById(elem_id).innerHTML = await response.text(); } catch (error) { console.log(error.message); } setTimeout(function () { getData(chart, url, sunrise) }, 5 * 60 * 1000); //renew data every 5 min. } function powerToString(power) { if (Math.abs(power) > 999) { power = power / 1000 return power.toPrecision(3) + " kW" } else { return Math.round(power) + " W" } } function polarToCartesian(centerX, centerY, radius, angleInDegrees) { var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; return { x: centerX + (radius * Math.cos(angleInRadians)), y: centerY + (radius * Math.sin(angleInRadians)) }; } function getRBGComponent(colRange, minCol, valRange, minVal, val) { return Math.round(((val - minVal) / valRange) * colRange + minCol) .toString(16) .toUpperCase() .padStart(2, '0'); } function assignColor(minCol, maxCol, minVal, maxVal, val) { var color = ""; var minR = parseInt(minCol.substring(1, 3), 16); var maxR = parseInt(maxCol.substring(1, 3), 16); var minG = parseInt(minCol.substring(3, 5), 16); var maxG = parseInt(maxCol.substring(3, 5), 16); var minB = parseInt(minCol.substring(5, 7), 16); var maxB = parseInt(maxCol.substring(5, 7), 16); var valsRange = maxVal - minVal; var rangeG = maxG - minG; var rangeR = maxR - minR; var rangeB = maxB - minB; if (val > maxVal) val = maxVal; else if (val < minVal) val = minVal; color = '#' + getRBGComponent(rangeR, minR, valsRange, minVal, val) + getRBGComponent(rangeG, minG, valsRange, minVal, val) + getRBGComponent(rangeB, minB, valsRange, minVal, val); return color; } function describeArc(x, y, radius, startAngle, endAngle) { if (endAngle > 288) { endAngle = 288; } var start = polarToCartesian(x, y, radius, endAngle); var end = polarToCartesian(x, y, radius, startAngle); var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1"; var d = [ "M", start.x, start.y, "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y ].join(" "); return d; } function updateValuesWeather(){ var div=document.getElementById("windDir"); div.style.transform = "rotate("+(90+Number(mqttData["weatherStation/windDeg"]))+"deg)"; document.getElementById("windSpd").innerHTML = mqttData["weatherStation/avgWindspeed"]; document.getElementById("humidity").innerHTML = mqttData["weatherStation/hum"]; document.getElementById("temp").innerHTML = mqttData["weatherStation/tempAmb"]; document.getElementById("windDirGust").style.transform = "rotate("+(90+Number(mqttData["weatherStation/gustDeg"]))+"deg)"; document.getElementById("windGust").innerHTML = mqttData["weatherStation/maxgust"]; document.getElementById("ambPress").innerHTML = Math.round(mqttData["weatherStation/qff"]*10)/10; }