Dashboard: Doppelungen zusammengelegt, Lade- und Renderlast gesenkt
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>
@@ -2,15 +2,6 @@
|
|||||||
|
|
||||||
require_once("../helper.php");
|
require_once("../helper.php");
|
||||||
$close = 0;
|
$close = 0;
|
||||||
function getSSLPage($url) {
|
|
||||||
$curlSession = curl_init();
|
|
||||||
curl_setopt($curlSession, CURLOPT_URL, $url);
|
|
||||||
curl_setopt($curlSession, CURLOPT_BINARYTRANSFER, true);
|
|
||||||
curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
$jsonData = json_decode(curl_exec($curlSession),true);
|
|
||||||
curl_close($curlSession);
|
|
||||||
return $jsonData;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkLogin()) {
|
if (checkLogin()) {
|
||||||
if (isset($_POST["sensorSelect1"])) { //if form war sent add an action
|
if (isset($_POST["sensorSelect1"])) { //if form war sent add an action
|
||||||
@@ -127,13 +118,6 @@ if (checkLogin()) {
|
|||||||
}
|
}
|
||||||
if (!$close) {
|
if (!$close) {
|
||||||
echo <<<ENDE
|
echo <<<ENDE
|
||||||
<style>
|
|
||||||
input[type='range']::-webkit-slider-runnable-track {
|
|
||||||
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
|
|
||||||
background-size: var(--background-size, 0%) 100%;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<!--begin::Form-->
|
<!--begin::Form-->
|
||||||
<form id="heater_form">
|
<form id="heater_form">
|
||||||
<div class="accordion" id="actionAccordion">
|
<div class="accordion" id="actionAccordion">
|
||||||
|
|||||||
@@ -55,87 +55,6 @@ if (checkLogin()) {
|
|||||||
$close = 1;
|
$close = 1;
|
||||||
}
|
}
|
||||||
if (!$close) {
|
if (!$close) {
|
||||||
echo <<<ENDE
|
$formId = "carEG_form";
|
||||||
<style>
|
include __DIR__ . "/carForm.php";
|
||||||
input[type='range']::-webkit-slider-runnable-track {
|
|
||||||
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
|
|
||||||
background-size: var(--background-size, 0%) 100%;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
<div class="d-grid gap-2 col-6 mx-auto my-4">
|
|
||||||
<button class="btn btn-primary" id="evStart/Stop">Laden starten</button>
|
|
||||||
</div>
|
|
||||||
<!--begin::Form-->
|
|
||||||
<form id="carEG_form">
|
|
||||||
<div class="card m-3">
|
|
||||||
<div class="card-header py-1 px-3">
|
|
||||||
<div class="card-title">Modus</div>
|
|
||||||
</div>
|
|
||||||
<!--begin::Body-->
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="radio" name="evMode" id="EV_Default" value="default">
|
|
||||||
<label class="form-check-label" for="EV_Default"> Immer Laden </label></input>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="radio" name="evMode" id="EV_Eco" value="eco">
|
|
||||||
<label class="form-check-label" for="EV_Eco"> Überschuss </label></input>
|
|
||||||
</div>
|
|
||||||
<div class="form-check disabled">
|
|
||||||
<input class="form-check-input" type="radio" name="evMode" id="EV_NextTrip" value="NextTrip">
|
|
||||||
<label class="form-check-label" for="EV_NextTrip"> Ladeplanung </label></input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card m-3">
|
|
||||||
<div class="card-header py-1 px-3">
|
|
||||||
<div class="card-title">Max. Ladestrom</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="radio" name="evAmp" id="EV_6A" value="6">
|
|
||||||
<label class="form-check-label" for="EV_6A"> 6A </label></input>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="radio" name="evAmp" id="EV_10A" value="10">
|
|
||||||
<label class="form-check-label" for="EV_10A"> 10A </label></input>
|
|
||||||
</div>
|
|
||||||
<div class="form-check disabled">
|
|
||||||
<input class="form-check-input" type="radio" name="evAmp" id="EV_16A" value="16">
|
|
||||||
<label class="form-check-label" for="EV_16A"> 16A </label></input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card m-3">
|
|
||||||
<div class="card-header py-1 px-3">
|
|
||||||
<div class="card-title">Ladeplanung</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="form-check">
|
|
||||||
<label class="form-label" for="addedCharge">Zusätzlich benötigte Ladung (%): </label>
|
|
||||||
<div style="font-size: 15px;color: #297195;display: inline-block;" id="modal-slider-label">sdf</div>
|
|
||||||
<input type="range" id="modal-slider" name="fte" class="form-range range-color-track" min="1" max="100" />
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">1%</span>
|
|
||||||
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">100%</span>
|
|
||||||
</div>
|
|
||||||
<!--<input name="fte" class="form-control" type="number" max="100" min="1" value="" />-->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="form-check">
|
|
||||||
<label class="form-label" for="planedTime">Zeitpunkt zudem geladen sein soll: </label>
|
|
||||||
<input id="EV_NextTripTime" name="ftt" class="form-control" size="2" type="time" value=""/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
ENDE;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Formular des Auto-Lademodals. carEG.php und carOG.php zeigen dasselbe
|
||||||
|
* Formular; nur die Ansteuerung der Wallbox dahinter unterscheidet sich.
|
||||||
|
* $formId trennt die beiden Formulare fuer das JavaScript.
|
||||||
|
*/
|
||||||
|
?>
|
||||||
|
<div class="d-grid gap-2 col-6 mx-auto my-4">
|
||||||
|
<button class="btn btn-primary" id="evStart/Stop">Laden starten</button>
|
||||||
|
</div>
|
||||||
|
<!--begin::Form-->
|
||||||
|
<form id="<?= $formId ?>">
|
||||||
|
<div class="card m-3">
|
||||||
|
<div class="card-header py-1 px-3">
|
||||||
|
<div class="card-title">Modus</div>
|
||||||
|
</div>
|
||||||
|
<!--begin::Body-->
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="radio" name="evMode" id="EV_Default" value="default">
|
||||||
|
<label class="form-check-label" for="EV_Default"> Immer Laden </label></input>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="radio" name="evMode" id="EV_Eco" value="eco">
|
||||||
|
<label class="form-check-label" for="EV_Eco"> Überschuss </label></input>
|
||||||
|
</div>
|
||||||
|
<div class="form-check disabled">
|
||||||
|
<input class="form-check-input" type="radio" name="evMode" id="EV_NextTrip" value="NextTrip">
|
||||||
|
<label class="form-check-label" for="EV_NextTrip"> Ladeplanung </label></input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card m-3">
|
||||||
|
<div class="card-header py-1 px-3">
|
||||||
|
<div class="card-title">Max. Ladestrom</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="radio" name="evAmp" id="EV_6A" value="6">
|
||||||
|
<label class="form-check-label" for="EV_6A"> 6A </label></input>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="radio" name="evAmp" id="EV_10A" value="10">
|
||||||
|
<label class="form-check-label" for="EV_10A"> 10A </label></input>
|
||||||
|
</div>
|
||||||
|
<div class="form-check disabled">
|
||||||
|
<input class="form-check-input" type="radio" name="evAmp" id="EV_16A" value="16">
|
||||||
|
<label class="form-check-label" for="EV_16A"> 16A </label></input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card m-3">
|
||||||
|
<div class="card-header py-1 px-3">
|
||||||
|
<div class="card-title">Ladeplanung</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="form-check">
|
||||||
|
<label class="form-label" for="addedCharge">Zusätzlich benötigte Ladung (%): </label>
|
||||||
|
<div style="font-size: 15px;color: #297195;display: inline-block;" id="modal-slider-label">sdf</div>
|
||||||
|
<input type="range" id="modal-slider" name="fte" class="form-range range-color-track" min="1" max="100" />
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">1%</span>
|
||||||
|
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">100%</span>
|
||||||
|
</div>
|
||||||
|
<!--<input name="fte" class="form-control" type="number" max="100" min="1" value="" />-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="form-check">
|
||||||
|
<label class="form-label" for="planedTime">Zeitpunkt zudem geladen sein soll: </label>
|
||||||
|
<input id="EV_NextTripTime" name="ftt" class="form-control" size="2" type="time" value=""/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
@@ -2,25 +2,16 @@
|
|||||||
|
|
||||||
require_once("../helper.php");
|
require_once("../helper.php");
|
||||||
|
|
||||||
function getSSLPage($url) {
|
|
||||||
$curlSession = curl_init();
|
|
||||||
curl_setopt($curlSession, CURLOPT_URL, $url);
|
|
||||||
curl_setopt($curlSession, CURLOPT_BINARYTRANSFER, true);
|
|
||||||
curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
$jsonData = json_decode(curl_exec($curlSession),true);
|
|
||||||
curl_close($curlSession);
|
|
||||||
return $jsonData;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkLogin()) {
|
if (checkLogin()) {
|
||||||
$close = 0;
|
$close = 0;
|
||||||
if (isset($_POST["evStart/Stop"])) {
|
if (isset($_POST["evStart/Stop"])) {
|
||||||
if ($_POST["evStart/Stop"] == "Laden starten") {
|
if ($_POST["evStart/Stop"] == "Laden starten") {
|
||||||
$close = 1;
|
$close = 1;
|
||||||
getSSLPage("http://192.168.179.122/api/set?frc=2");
|
httpGetJson("http://192.168.179.122/api/set?frc=2");
|
||||||
} else if ($_POST["evStart/Stop"] == "Laden stoppen") {
|
} else if ($_POST["evStart/Stop"] == "Laden stoppen") {
|
||||||
$close = 1;
|
$close = 1;
|
||||||
getSSLPage("http://192.168.179.122/api/set?frc=1");
|
httpGetJson("http://192.168.179.122/api/set?frc=1");
|
||||||
}
|
}
|
||||||
$close = 1;
|
$close = 1;
|
||||||
} else if (isset($_POST["evMode"])) {
|
} else if (isset($_POST["evMode"])) {
|
||||||
@@ -37,23 +28,23 @@ if (checkLogin()) {
|
|||||||
if ($_POST["evMode"] == "eco") {
|
if ($_POST["evMode"] == "eco") {
|
||||||
$close = 1;
|
$close = 1;
|
||||||
if ($_POST["ftt"] && $_POST["fte"] > 0) {
|
if ($_POST["ftt"] && $_POST["fte"] > 0) {
|
||||||
getSSLPage("http://192.168.179.122/api/set?ate=" . $_POST["fte"] . "&att=" . $seconds . "&=" . $_POST["evAmp"] . "&fup=true&lmo=4");
|
httpGetJson("http://192.168.179.122/api/set?ate=" . $_POST["fte"] . "&att=" . $seconds . "&=" . $_POST["evAmp"] . "&fup=true&lmo=4");
|
||||||
} else {
|
} else {
|
||||||
getSSLPage("http://192.168.179.122/api/set?amp=" . $_POST["evAmp"] . "&fup=true&lmo=4");
|
httpGetJson("http://192.168.179.122/api/set?amp=" . $_POST["evAmp"] . "&fup=true&lmo=4");
|
||||||
}
|
}
|
||||||
} else if ($_POST["evMode"] == "default") {
|
} else if ($_POST["evMode"] == "default") {
|
||||||
$close = 1;
|
$close = 1;
|
||||||
if ($_POST["ftt"] && $_POST["fte"] > 0) {
|
if ($_POST["ftt"] && $_POST["fte"] > 0) {
|
||||||
getSSLPage("http://192.168.179.122/api/set?ate=" . $_POST["fte"] . "&att=" . $seconds . "&=" . $_POST["evAmp"] . "&fup=true&lmo=3");
|
httpGetJson("http://192.168.179.122/api/set?ate=" . $_POST["fte"] . "&att=" . $seconds . "&=" . $_POST["evAmp"] . "&fup=true&lmo=3");
|
||||||
} else {
|
} else {
|
||||||
getSSLPage("http://192.168.179.122/api/set?amp=" . $_POST["evAmp"] . "&fup=true&lmo=3");
|
httpGetJson("http://192.168.179.122/api/set?amp=" . $_POST["evAmp"] . "&fup=true&lmo=3");
|
||||||
}
|
}
|
||||||
} else if ($_POST["evMode"] == "NextTrip") {
|
} else if ($_POST["evMode"] == "NextTrip") {
|
||||||
$close = 1;
|
$close = 1;
|
||||||
if ($_POST["ftt"] && $_POST["fte"] > 0) {
|
if ($_POST["ftt"] && $_POST["fte"] > 0) {
|
||||||
getSSLPage("http://192.168.179.122/api/set?ate=" . $_POST["fte"] . "&att=" . $seconds . "&=" . $_POST["evAmp"] . "&fup=true&lmo=5");
|
httpGetJson("http://192.168.179.122/api/set?ate=" . $_POST["fte"] . "&att=" . $seconds . "&=" . $_POST["evAmp"] . "&fup=true&lmo=5");
|
||||||
} else {
|
} else {
|
||||||
getSSLPage("http://192.168.179.122/api/set?amp=" . $_POST["evAmp"] . "&fup=true&lmo=5");
|
httpGetJson("http://192.168.179.122/api/set?amp=" . $_POST["evAmp"] . "&fup=true&lmo=5");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$close = 1;
|
$close = 1;
|
||||||
@@ -62,87 +53,6 @@ if (checkLogin()) {
|
|||||||
$close = 1;
|
$close = 1;
|
||||||
}
|
}
|
||||||
if (!$close) {
|
if (!$close) {
|
||||||
echo <<<ENDE
|
$formId = "carOG_form";
|
||||||
<style>
|
include __DIR__ . "/carForm.php";
|
||||||
input[type='range']::-webkit-slider-runnable-track {
|
|
||||||
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
|
|
||||||
background-size: var(--background-size, 0%) 100%;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div class="d-grid gap-2 col-6 mx-auto my-4">
|
|
||||||
<button class="btn btn-primary" id="evStart/Stop">Laden starten</button>
|
|
||||||
</div>
|
|
||||||
<!--begin::Form-->
|
|
||||||
<form id="carOG_form">
|
|
||||||
<div class="card m-3">
|
|
||||||
<div class="card-header py-1 px-3">
|
|
||||||
<div class="card-title">Modus</div>
|
|
||||||
</div>
|
|
||||||
<!--begin::Body-->
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="radio" name="evMode" id="EV_Default" value="default">
|
|
||||||
<label class="form-check-label" for="EV_Default"> Immer Laden </label></input>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="radio" name="evMode" id="EV_Eco" value="eco">
|
|
||||||
<label class="form-check-label" for="EV_Eco"> Überschuss </label></input>
|
|
||||||
</div>
|
|
||||||
<div class="form-check disabled">
|
|
||||||
<input class="form-check-input" type="radio" name="evMode" id="EV_NextTrip" value="NextTrip">
|
|
||||||
<label class="form-check-label" for="EV_NextTrip"> Ladeplanung </label></input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card m-3">
|
|
||||||
<div class="card-header py-1 px-3">
|
|
||||||
<div class="card-title">Max. Ladestrom</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="radio" name="evAmp" id="EV_6A" value="6">
|
|
||||||
<label class="form-check-label" for="EV_6A"> 6A </label></input>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="radio" name="evAmp" id="EV_10A" value="10">
|
|
||||||
<label class="form-check-label" for="EV_10A"> 10A </label></input>
|
|
||||||
</div>
|
|
||||||
<div class="form-check disabled">
|
|
||||||
<input class="form-check-input" type="radio" name="evAmp" id="EV_16A" value="16">
|
|
||||||
<label class="form-check-label" for="EV_16A"> 16A </label></input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card m-3">
|
|
||||||
<div class="card-header py-1 px-3">
|
|
||||||
<div class="card-title">Ladeplanung</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="form-check">
|
|
||||||
<label class="form-label" for="addedCharge">Zusätzlich benötigte Ladung (%): </label>
|
|
||||||
<div style="font-size: 15px;color: #297195;display: inline-block;" id="modal-slider-label">sdf</div>
|
|
||||||
<input type="range" id="modal-slider" name="fte" class="form-range range-color-track" min="1" max="100" />
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">1%</span>
|
|
||||||
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">100%</span>
|
|
||||||
</div>
|
|
||||||
<!--<input name="fte" class="form-control" type="number" max="100" min="1" value="" />-->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="form-check">
|
|
||||||
<label class="form-label" for="planedTime">Zeitpunkt zudem geladen sein soll: </label>
|
|
||||||
<input id="EV_NextTripTime" name="ftt" class="form-control" size="2" type="time" value=""/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
ENDE;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Gemeinsame Bausteine für die Chart-Endpunkte in ajax/.
|
||||||
|
*
|
||||||
|
* Alle Endpunkte liefern Chart.js-Daten im gleichen Format: eine Abfrage mit
|
||||||
|
* einer Spalte "time" (Beschriftung) und je einer Spalte pro Datenreihe.
|
||||||
|
* chartDataset() legt das Styling einer Reihe fest, buildChartData() baut
|
||||||
|
* daraus das fertige {labels, datasets}-Objekt.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling für eine Datenreihe. $filled merkt sich über die Reihen hinweg,
|
||||||
|
* ob die unterste Fläche des Stapels schon gegen die Nulllinie gefüllt wurde.
|
||||||
|
*/
|
||||||
|
function chartDataset($name, $linecolors, &$filled)
|
||||||
|
{
|
||||||
|
$color = isset($linecolors[$name]) ? $linecolors[$name] : "#888888";
|
||||||
|
|
||||||
|
$dataset = (object)[];
|
||||||
|
$dataset->label = $name;
|
||||||
|
$dataset->data = [];
|
||||||
|
$dataset->borderColor = $color;
|
||||||
|
$dataset->backgroundColor = $color . "55";
|
||||||
|
$dataset->borderWidth = 1;
|
||||||
|
$dataset->pointRadius = 0;
|
||||||
|
$dataset->pointHoverRadius = 5;
|
||||||
|
$dataset->tension = 0.2;
|
||||||
|
|
||||||
|
if ($name == "Solarleistung") {
|
||||||
|
$dataset->stack = "SolarPwr";
|
||||||
|
$dataset->fill = "none";
|
||||||
|
$dataset->yAxisID = 'y';
|
||||||
|
} else if ($name == "Ladestand") {
|
||||||
|
$dataset->stack = "Charge";
|
||||||
|
$dataset->fill = "none";
|
||||||
|
$dataset->yAxisID = 'y1';
|
||||||
|
} else {
|
||||||
|
$dataset->stack = "Consumers";
|
||||||
|
if (!$filled) {
|
||||||
|
$filled = true;
|
||||||
|
$dataset->fill = "origin";
|
||||||
|
} else {
|
||||||
|
$dataset->fill = "-1";
|
||||||
|
}
|
||||||
|
$dataset->yAxisID = 'y';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dataset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Führt $query aus und baut daraus das Chart.js-Objekt.
|
||||||
|
* $labelFactor multipliziert die Zeitspalte (1 für Textbeschriftungen,
|
||||||
|
* 1000 für Unix-Zeitstempel, die Chart.js in Millisekunden erwartet).
|
||||||
|
*/
|
||||||
|
function buildChartData($mysql, $query, $linecolors, $labelFactor = 1)
|
||||||
|
{
|
||||||
|
$obj = (object)[];
|
||||||
|
$obj->labels = [];
|
||||||
|
$obj->datasets = [];
|
||||||
|
|
||||||
|
$result = mysqli_query($mysql, $query);
|
||||||
|
if (!$result) {
|
||||||
|
// Nicht ins Ergebnis schreiben - der Aufrufer liefert JSON aus.
|
||||||
|
error_log("chartData: " . mysqli_error($mysql));
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
if ($result->num_rows < 2) {
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
$column = []; // Spaltenname -> Position in $obj->datasets
|
||||||
|
$filled = false;
|
||||||
|
foreach ($result->fetch_fields() as $field) {
|
||||||
|
if ($field->name == "time") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$column[$field->name] = count($obj->datasets);
|
||||||
|
$obj->datasets[] = chartDataset($field->name, $linecolors, $filled);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($row = $result->fetch_assoc()) {
|
||||||
|
foreach ($row as $name => $value) {
|
||||||
|
if ($name == "time") {
|
||||||
|
$obj->labels[] = $labelFactor == 1 ? $value : $value * $labelFactor;
|
||||||
|
} else {
|
||||||
|
$obj->datasets[$column[$name]]->data[] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Aggregierte Energiedaten für die Historie-Seite.
|
||||||
|
* Ersetzt getConsData_{month,year,decade}.php und getProdData_{month,year,decade}.php.
|
||||||
|
*
|
||||||
|
* Aufruf: energyHistory.php?series=prod|cons&range=month|year|decade
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once("../helper.php");
|
||||||
|
require_once("./chartData.php");
|
||||||
|
|
||||||
|
// Zeitraum -> [Format der Beschriftung, Filter auf datetime]
|
||||||
|
$ranges = [
|
||||||
|
"month" => ["'%d.%b.'", "DATE_FORMAT(datetime,'%Y%m%d') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 1 MONTH),'%Y%m%d')"],
|
||||||
|
"year" => ["'%b. %y'", "DATE_FORMAT(datetime,'%Y%m') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 13 MONTH),'%Y%m')"],
|
||||||
|
"decade" => ["'%Y'", "DATE_FORMAT(datetime,'%Y') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 10 YEAR),'%Y')"],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Datenreihen je Diagramm. Beide teilen sich Solarertrag und Heizstab und
|
||||||
|
// unterscheiden sich nur darin, wohin die Energie fließt (prod) bzw. woher
|
||||||
|
// sie kommt (cons).
|
||||||
|
$series = [
|
||||||
|
"prod" => "SUM(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0) - heaterPwr/12) AS Direktverbrauch,
|
||||||
|
SUM(heaterPwr/12) AS Heizstab,
|
||||||
|
SUM(IF(battP < 0, -battP/12,0)) AS Batterieladung,
|
||||||
|
SUM(gridPfeed/12) AS Einspeisung",
|
||||||
|
"cons" => "SUM(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0) - heaterPwr/12) AS Solarverbrauch,
|
||||||
|
SUM(heaterPwr/12) AS Heizstab,
|
||||||
|
SUM(IF(battP > 0, battP/12,0)) AS Batteriebezug,
|
||||||
|
SUM(gridPcons/12) AS Netzbezug",
|
||||||
|
];
|
||||||
|
|
||||||
|
$linecolors["Direktverbrauch"] = "#FFFF00";
|
||||||
|
$linecolors["Solarverbrauch"] = "#FFFF00";
|
||||||
|
$linecolors["UG"] = "#FFaa00";
|
||||||
|
$linecolors["OG"] = "#FF4400";
|
||||||
|
$linecolors["Auto UG"] = "#00aaFF";
|
||||||
|
$linecolors["Auto OG"] = "#0044FF";
|
||||||
|
$linecolors["Heizstab"] = "#FF6600";
|
||||||
|
$linecolors["Batterieladung"] = "#00aa00";
|
||||||
|
$linecolors["Batteriebezug"] = "#00aa00";
|
||||||
|
$linecolors["Einspeisung"] = "#FF0000";
|
||||||
|
$linecolors["Netzbezug"] = "#FF0000";
|
||||||
|
$linecolors["Ladestand"] = "#00aa00";
|
||||||
|
$linecolors["Vorhersage"] = "#2222FF";
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
$rangeKey = isset($_GET["range"]) ? $_GET["range"] : "";
|
||||||
|
$seriesKey = isset($_GET["series"]) ? $_GET["series"] : "";
|
||||||
|
if (!isset($ranges[$rangeKey]) || !isset($series[$seriesKey])) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Unbekannter Zeitraum oder Datenreihe."]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
list($labelFormat, $filter) = $ranges[$rangeKey];
|
||||||
|
|
||||||
|
$obj = (object)[];
|
||||||
|
$obj->labels = [];
|
||||||
|
$obj->datasets = [];
|
||||||
|
|
||||||
|
if (checkLogin()) {
|
||||||
|
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
|
||||||
|
$query = "SELECT
|
||||||
|
DATE_FORMAT(datetime, $labelFormat) AS 'time',
|
||||||
|
" . $series[$seriesKey] . "
|
||||||
|
FROM EnergyFlow
|
||||||
|
WHERE $filter
|
||||||
|
GROUP BY DATE_FORMAT(datetime, $labelFormat)
|
||||||
|
ORDER BY datetime ; ";
|
||||||
|
$obj = buildChartData($mysql, $query, $linecolors);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($obj);
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require_once("../helper.php");
|
|
||||||
|
|
||||||
$consQuery = "SELECT
|
|
||||||
DATE_FORMAT(datetime,'%Y') AS 'time',
|
|
||||||
SUM(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0)- heaterPwr/12) Solarverbrauch,
|
|
||||||
SUM(heaterPwr/12) AS Heizstab,
|
|
||||||
SUM(IF(battP > 0, battP/12,0)) AS Batteriebezug,
|
|
||||||
SUM(gridPcons/12) AS Netzbezug
|
|
||||||
FROM EnergyFlow
|
|
||||||
WHERE DATE_FORMAT(datetime,'%Y') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 10 YEAR),'%Y')
|
|
||||||
GROUP BY time
|
|
||||||
ORDER BY datetime ; ";
|
|
||||||
|
|
||||||
$linecolors["Solarverbrauch"] = "#FFFF00";
|
|
||||||
$linecolors["UG"] = "#FFaa00";
|
|
||||||
$linecolors["OG"] = "#FF4400";
|
|
||||||
$linecolors["Auto UG"] = "#00aaFF";
|
|
||||||
$linecolors["Auto OG"] = "#0044FF";
|
|
||||||
$linecolors["Heizstab"] = "#FF6600";
|
|
||||||
$linecolors["Batteriebezug"] = "#00aa00";
|
|
||||||
$linecolors["Netzbezug"] = "#FF0000";
|
|
||||||
$linecolors["Ladestand"] = "#00aa00";
|
|
||||||
$linecolors["Vorhersage"] = "#2222FF";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (checkLogin()) {
|
|
||||||
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
|
|
||||||
$result = mysqli_query($mysql, $consQuery);
|
|
||||||
if(!$result){
|
|
||||||
echo "Error:<br>".mysqli_error($mysql)."<br />";
|
|
||||||
}
|
|
||||||
$obj = (object)[]; // Cast empty array to object
|
|
||||||
$obj->labels = [];
|
|
||||||
$obj->datasets = [];
|
|
||||||
$i = 0;
|
|
||||||
$filled = 0;
|
|
||||||
if ($result->num_rows > 1) {
|
|
||||||
$ii = 0;
|
|
||||||
$row = $result->fetch_assoc();
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
$dataset = (object)[];
|
|
||||||
if ($name != "time") {
|
|
||||||
$dataset->borderColor = $linecolors[$name];
|
|
||||||
$dataset->backgroundColor = $linecolors[$name]."55";
|
|
||||||
$dataset->borderWidth=1;
|
|
||||||
$dataset->pointRadius= 0;
|
|
||||||
$dataset->pointHoverRadius= 5;
|
|
||||||
$dataset->tension=0.2;
|
|
||||||
if ($name == "Solarleistung") {
|
|
||||||
$dataset->stack = "SolarPwr";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
} else if ($name == "Ladestand") {
|
|
||||||
$dataset->stack = "Charge";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y1';
|
|
||||||
} else {
|
|
||||||
$dataset->stack = "Consumers";
|
|
||||||
if ($filled == 0) {
|
|
||||||
$filled = 1;
|
|
||||||
$dataset->fill = "origin";
|
|
||||||
} else {
|
|
||||||
$dataset->fill = "-1";
|
|
||||||
}
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
}
|
|
||||||
$dataset->label = $name;
|
|
||||||
|
|
||||||
$dataset->data[] = $value;
|
|
||||||
$obj->datasets[] = clone $dataset;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$ii = 0;
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
if ($name != "time") {
|
|
||||||
$obj->datasets[$ii]->data[] = $value;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//header('Content-Type: application/json');
|
|
||||||
echo json_encode($obj);
|
|
||||||
//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]}]}';
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require_once("../helper.php");
|
|
||||||
|
|
||||||
$consQuery = "SELECT
|
|
||||||
DATE_FORMAT(datetime, '%d.%b.') AS 'time',
|
|
||||||
SUM(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0)- heaterPwr/12) Solarverbrauch,
|
|
||||||
SUM(heaterPwr/12) AS Heizstab,
|
|
||||||
SUM(IF(battP > 0, battP/12,0)) AS Batteriebezug,
|
|
||||||
SUM(gridPcons/12) AS Netzbezug
|
|
||||||
FROM EnergyFlow
|
|
||||||
WHERE DATE_FORMAT(datetime,'%Y%m%d') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 1 MONTH),'%Y%m%d')
|
|
||||||
GROUP BY DATE_FORMAT(datetime, '%d.%b.')
|
|
||||||
ORDER BY datetime ; ";
|
|
||||||
|
|
||||||
$linecolors["Solarverbrauch"] = "#FFFF00";
|
|
||||||
$linecolors["UG"] = "#FFaa00";
|
|
||||||
$linecolors["OG"] = "#FF4400";
|
|
||||||
$linecolors["Auto UG"] = "#00aaFF";
|
|
||||||
$linecolors["Auto OG"] = "#0044FF";
|
|
||||||
$linecolors["Heizstab"] = "#FF6600";
|
|
||||||
$linecolors["Batteriebezug"] = "#00aa00";
|
|
||||||
$linecolors["Netzbezug"] = "#FF0000";
|
|
||||||
$linecolors["Ladestand"] = "#00aa00";
|
|
||||||
$linecolors["Vorhersage"] = "#2222FF";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (checkLogin()) {
|
|
||||||
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
|
|
||||||
$result = mysqli_query($mysql, $consQuery);
|
|
||||||
if(!$result){
|
|
||||||
echo "Error:<br>".mysqli_error($mysql)."<br />";
|
|
||||||
}
|
|
||||||
$obj = (object)[]; // Cast empty array to object
|
|
||||||
$obj->labels = [];
|
|
||||||
$obj->datasets = [];
|
|
||||||
$i = 0;
|
|
||||||
$filled = 0;
|
|
||||||
if ($result->num_rows > 1) {
|
|
||||||
$ii = 0;
|
|
||||||
$row = $result->fetch_assoc();
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
$dataset = (object)[];
|
|
||||||
if ($name != "time") {
|
|
||||||
$dataset->borderColor = $linecolors[$name];
|
|
||||||
$dataset->backgroundColor = $linecolors[$name]."55";
|
|
||||||
$dataset->borderWidth=1;
|
|
||||||
$dataset->pointRadius= 0;
|
|
||||||
$dataset->pointHoverRadius= 5;
|
|
||||||
$dataset->tension=0.2;
|
|
||||||
if ($name == "Solarleistung") {
|
|
||||||
$dataset->stack = "SolarPwr";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
} else if ($name == "Ladestand") {
|
|
||||||
$dataset->stack = "Charge";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y1';
|
|
||||||
} else {
|
|
||||||
$dataset->stack = "Consumers";
|
|
||||||
if ($filled == 0) {
|
|
||||||
$filled = 1;
|
|
||||||
$dataset->fill = "origin";
|
|
||||||
} else {
|
|
||||||
$dataset->fill = "-1";
|
|
||||||
}
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
}
|
|
||||||
$dataset->label = $name;
|
|
||||||
|
|
||||||
$dataset->data[] = $value;
|
|
||||||
$obj->datasets[] = clone $dataset;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$ii = 0;
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
if ($name != "time") {
|
|
||||||
$obj->datasets[$ii]->data[] = $value;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//header('Content-Type: application/json');
|
|
||||||
echo json_encode($obj);
|
|
||||||
//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]}]}';
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require_once("../helper.php");
|
|
||||||
|
|
||||||
$consQuery = "SELECT
|
|
||||||
DATE_FORMAT(datetime, '%b. %y') AS 'time',
|
|
||||||
SUM(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0)- heaterPwr/12) Solarverbrauch,
|
|
||||||
SUM(heaterPwr/12) AS Heizstab,
|
|
||||||
SUM(IF(battP > 0, battP/12,0)) AS Batteriebezug,
|
|
||||||
SUM(gridPcons/12) AS Netzbezug
|
|
||||||
FROM EnergyFlow
|
|
||||||
WHERE DATE_FORMAT(datetime,'%Y%m') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 13 MONTH),'%Y%m')
|
|
||||||
GROUP BY DATE_FORMAT(datetime, '%b. %y')
|
|
||||||
ORDER BY datetime ; ";
|
|
||||||
|
|
||||||
$linecolors["Solarverbrauch"] = "#FFFF00";
|
|
||||||
$linecolors["UG"] = "#FFaa00";
|
|
||||||
$linecolors["OG"] = "#FF4400";
|
|
||||||
$linecolors["Auto UG"] = "#00aaFF";
|
|
||||||
$linecolors["Auto OG"] = "#0044FF";
|
|
||||||
$linecolors["Heizstab"] = "#FF6600";
|
|
||||||
$linecolors["Batteriebezug"] = "#00aa00";
|
|
||||||
$linecolors["Netzbezug"] = "#FF0000";
|
|
||||||
$linecolors["Ladestand"] = "#00aa00";
|
|
||||||
$linecolors["Vorhersage"] = "#2222FF";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (checkLogin()) {
|
|
||||||
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
|
|
||||||
$result = mysqli_query($mysql, $consQuery);
|
|
||||||
if(!$result){
|
|
||||||
echo "Error:<br>".mysqli_error($mysql)."<br />";
|
|
||||||
}
|
|
||||||
$obj = (object)[]; // Cast empty array to object
|
|
||||||
$obj->labels = [];
|
|
||||||
$obj->datasets = [];
|
|
||||||
$i = 0;
|
|
||||||
$filled = 0;
|
|
||||||
if ($result->num_rows > 1) {
|
|
||||||
$ii = 0;
|
|
||||||
$row = $result->fetch_assoc();
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
$dataset = (object)[];
|
|
||||||
if ($name != "time") {
|
|
||||||
$dataset->borderColor = $linecolors[$name];
|
|
||||||
$dataset->backgroundColor = $linecolors[$name]."55";
|
|
||||||
$dataset->borderWidth=1;
|
|
||||||
$dataset->pointRadius= 0;
|
|
||||||
$dataset->pointHoverRadius= 5;
|
|
||||||
$dataset->tension=0.2;
|
|
||||||
if ($name == "Solarleistung") {
|
|
||||||
$dataset->stack = "SolarPwr";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
} else if ($name == "Ladestand") {
|
|
||||||
$dataset->stack = "Charge";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y1';
|
|
||||||
} else {
|
|
||||||
$dataset->stack = "Consumers";
|
|
||||||
if ($filled == 0) {
|
|
||||||
$filled = 1;
|
|
||||||
$dataset->fill = "origin";
|
|
||||||
} else {
|
|
||||||
$dataset->fill = "-1";
|
|
||||||
}
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
}
|
|
||||||
$dataset->label = $name;
|
|
||||||
|
|
||||||
$dataset->data[] = $value;
|
|
||||||
$obj->datasets[] = clone $dataset;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$ii = 0;
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
if ($name != "time") {
|
|
||||||
$obj->datasets[$ii]->data[] = $value;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//header('Content-Type: application/json');
|
|
||||||
echo json_encode($obj);
|
|
||||||
//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]}]}';
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require_once("../helper.php");
|
|
||||||
|
|
||||||
$consQuery = "SELECT
|
|
||||||
DATE_FORMAT(datetime,'%Y') AS 'time',
|
|
||||||
SUM(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0) - heaterPwr/12) Direktverbrauch,
|
|
||||||
SUM(heaterPwr/12) AS Heizstab,
|
|
||||||
SUM(IF(battP < 0, -battP/12,0)) AS Batterieladung,
|
|
||||||
SUM(gridPfeed/12) AS Einspeisung
|
|
||||||
FROM EnergyFlow
|
|
||||||
WHERE DATE_FORMAT(datetime,'%Y') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 10 YEAR),'%Y')
|
|
||||||
GROUP BY DATE_FORMAT(datetime, '%Y')
|
|
||||||
ORDER BY datetime ; ";
|
|
||||||
|
|
||||||
$linecolors["Direktverbrauch"] = "#FFFF00";
|
|
||||||
$linecolors["UG"] = "#FFaa00";
|
|
||||||
$linecolors["OG"] = "#FF4400";
|
|
||||||
$linecolors["Auto UG"] = "#00aaFF";
|
|
||||||
$linecolors["Auto OG"] = "#0044FF";
|
|
||||||
$linecolors["Heizstab"] = "#FF6600";
|
|
||||||
$linecolors["Batterieladung"] = "#00aa00";
|
|
||||||
$linecolors["Einspeisung"] = "#FF0000";
|
|
||||||
$linecolors["Ladestand"] = "#00aa00";
|
|
||||||
$linecolors["Vorhersage"] = "#2222FF";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (checkLogin()) {
|
|
||||||
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
|
|
||||||
$result = mysqli_query($mysql, $consQuery);
|
|
||||||
if(!$result){
|
|
||||||
echo "Error:<br>".mysqli_error($mysql)."<br />";
|
|
||||||
}
|
|
||||||
$obj = (object)[]; // Cast empty array to object
|
|
||||||
$obj->labels = [];
|
|
||||||
$obj->datasets = [];
|
|
||||||
$i = 0;
|
|
||||||
$filled = 0;
|
|
||||||
if ($result->num_rows > 1) {
|
|
||||||
$ii = 0;
|
|
||||||
$row = $result->fetch_assoc();
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
$dataset = (object)[];
|
|
||||||
if ($name != "time") {
|
|
||||||
$dataset->borderColor = $linecolors[$name];
|
|
||||||
$dataset->backgroundColor = $linecolors[$name]."55";
|
|
||||||
$dataset->borderWidth=1;
|
|
||||||
$dataset->pointRadius= 0;
|
|
||||||
$dataset->pointHoverRadius= 5;
|
|
||||||
$dataset->tension=0.2;
|
|
||||||
if ($name == "Solarleistung") {
|
|
||||||
$dataset->stack = "SolarPwr";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
} else if ($name == "Ladestand") {
|
|
||||||
$dataset->stack = "Charge";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y1';
|
|
||||||
} else {
|
|
||||||
$dataset->stack = "Consumers";
|
|
||||||
if ($filled == 0) {
|
|
||||||
$filled = 1;
|
|
||||||
$dataset->fill = "origin";
|
|
||||||
} else {
|
|
||||||
$dataset->fill = "-1";
|
|
||||||
}
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
}
|
|
||||||
$dataset->label = $name;
|
|
||||||
|
|
||||||
$dataset->data[] = $value;
|
|
||||||
$obj->datasets[] = clone $dataset;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$ii = 0;
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
if ($name != "time") {
|
|
||||||
$obj->datasets[$ii]->data[] = $value;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//header('Content-Type: application/json');
|
|
||||||
echo json_encode($obj);
|
|
||||||
//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]}]}';
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require_once("../helper.php");
|
|
||||||
|
|
||||||
$consQuery = "SELECT
|
|
||||||
DATE_FORMAT(datetime, '%d.%b.') AS 'time',
|
|
||||||
SUM(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0) - heaterPwr/12) Direktverbrauch,
|
|
||||||
SUM(heaterPwr/12) AS Heizstab,
|
|
||||||
SUM(IF(battP < 0, -battP/12,0)) AS Batterieladung,
|
|
||||||
SUM(gridPfeed/12) AS Einspeisung
|
|
||||||
FROM EnergyFlow
|
|
||||||
WHERE DATE_FORMAT(datetime,'%Y%m%d') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 1 MONTH),'%Y%m%d')
|
|
||||||
GROUP BY DATE_FORMAT(datetime, '%d.%b.')
|
|
||||||
ORDER BY datetime ; ";
|
|
||||||
|
|
||||||
$linecolors["Direktverbrauch"] = "#FFFF00";
|
|
||||||
$linecolors["UG"] = "#FFaa00";
|
|
||||||
$linecolors["OG"] = "#FF4400";
|
|
||||||
$linecolors["Auto UG"] = "#00aaFF";
|
|
||||||
$linecolors["Auto OG"] = "#0044FF";
|
|
||||||
$linecolors["Heizstab"] = "#FF6600";
|
|
||||||
$linecolors["Batterieladung"] = "#00aa00";
|
|
||||||
$linecolors["Einspeisung"] = "#FF0000";
|
|
||||||
$linecolors["Ladestand"] = "#00aa00";
|
|
||||||
$linecolors["Vorhersage"] = "#2222FF";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (checkLogin()) {
|
|
||||||
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
|
|
||||||
$result = mysqli_query($mysql, $consQuery);
|
|
||||||
if(!$result){
|
|
||||||
echo "Error:<br>".mysqli_error($mysql)."<br />";
|
|
||||||
}
|
|
||||||
$obj = (object)[]; // Cast empty array to object
|
|
||||||
$obj->labels = [];
|
|
||||||
$obj->datasets = [];
|
|
||||||
$i = 0;
|
|
||||||
$filled = 0;
|
|
||||||
if ($result->num_rows > 1) {
|
|
||||||
$ii = 0;
|
|
||||||
$row = $result->fetch_assoc();
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
$dataset = (object)[];
|
|
||||||
if ($name != "time") {
|
|
||||||
$dataset->borderColor = $linecolors[$name];
|
|
||||||
$dataset->backgroundColor = $linecolors[$name]."55";
|
|
||||||
$dataset->borderWidth=1;
|
|
||||||
$dataset->pointRadius= 0;
|
|
||||||
$dataset->pointHoverRadius= 5;
|
|
||||||
$dataset->tension=0.2;
|
|
||||||
if ($name == "Solarleistung") {
|
|
||||||
$dataset->stack = "SolarPwr";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
} else if ($name == "Ladestand") {
|
|
||||||
$dataset->stack = "Charge";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y1';
|
|
||||||
} else {
|
|
||||||
$dataset->stack = "Consumers";
|
|
||||||
if ($filled == 0) {
|
|
||||||
$filled = 1;
|
|
||||||
$dataset->fill = "origin";
|
|
||||||
} else {
|
|
||||||
$dataset->fill = "-1";
|
|
||||||
}
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
}
|
|
||||||
$dataset->label = $name;
|
|
||||||
|
|
||||||
$dataset->data[] = $value;
|
|
||||||
$obj->datasets[] = clone $dataset;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$ii = 0;
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
if ($name != "time") {
|
|
||||||
$obj->datasets[$ii]->data[] = $value;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//header('Content-Type: application/json');
|
|
||||||
echo json_encode($obj);
|
|
||||||
//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]}]}';
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require_once("../helper.php");
|
|
||||||
|
|
||||||
$consQuery = "SELECT
|
|
||||||
DATE_FORMAT(datetime,'%b. %y') AS 'time',
|
|
||||||
SUM(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0) - heaterPwr/12) Direktverbrauch,
|
|
||||||
SUM(heaterPwr/12) AS Heizstab,
|
|
||||||
SUM(IF(battP < 0, -battP/12,0)) AS Batterieladung,
|
|
||||||
SUM(gridPfeed/12) AS Einspeisung
|
|
||||||
FROM EnergyFlow
|
|
||||||
WHERE DATE_FORMAT(datetime,'%Y%m') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 13 MONTH),'%Y%m')
|
|
||||||
GROUP BY DATE_FORMAT(datetime, '%b. %y')
|
|
||||||
ORDER BY datetime ; ";
|
|
||||||
|
|
||||||
$linecolors["Direktverbrauch"] = "#FFFF00";
|
|
||||||
$linecolors["UG"] = "#FFaa00";
|
|
||||||
$linecolors["OG"] = "#FF4400";
|
|
||||||
$linecolors["Auto UG"] = "#00aaFF";
|
|
||||||
$linecolors["Auto OG"] = "#0044FF";
|
|
||||||
$linecolors["Heizstab"] = "#FF6600";
|
|
||||||
$linecolors["Batterieladung"] = "#00aa00";
|
|
||||||
$linecolors["Einspeisung"] = "#FF0000";
|
|
||||||
$linecolors["Ladestand"] = "#00aa00";
|
|
||||||
$linecolors["Vorhersage"] = "#2222FF";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (checkLogin()) {
|
|
||||||
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
|
|
||||||
$result = mysqli_query($mysql, $consQuery);
|
|
||||||
if(!$result){
|
|
||||||
echo "Error:<br>".mysqli_error($mysql)."<br />";
|
|
||||||
}
|
|
||||||
$obj = (object)[]; // Cast empty array to object
|
|
||||||
$obj->labels = [];
|
|
||||||
$obj->datasets = [];
|
|
||||||
$i = 0;
|
|
||||||
$filled = 0;
|
|
||||||
if ($result->num_rows > 1) {
|
|
||||||
$ii = 0;
|
|
||||||
$row = $result->fetch_assoc();
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
$dataset = (object)[];
|
|
||||||
if ($name != "time") {
|
|
||||||
$dataset->borderColor = $linecolors[$name];
|
|
||||||
$dataset->backgroundColor = $linecolors[$name]."55";
|
|
||||||
$dataset->borderWidth=1;
|
|
||||||
$dataset->pointRadius= 0;
|
|
||||||
$dataset->pointHoverRadius= 5;
|
|
||||||
$dataset->tension=0.2;
|
|
||||||
if ($name == "Solarleistung") {
|
|
||||||
$dataset->stack = "SolarPwr";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
} else if ($name == "Ladestand") {
|
|
||||||
$dataset->stack = "Charge";
|
|
||||||
$dataset->fill = "none";
|
|
||||||
$dataset->yAxisID = 'y1';
|
|
||||||
} else {
|
|
||||||
$dataset->stack = "Consumers";
|
|
||||||
if ($filled == 0) {
|
|
||||||
$filled = 1;
|
|
||||||
$dataset->fill = "origin";
|
|
||||||
} else {
|
|
||||||
$dataset->fill = "-1";
|
|
||||||
}
|
|
||||||
$dataset->yAxisID = 'y';
|
|
||||||
}
|
|
||||||
$dataset->label = $name;
|
|
||||||
|
|
||||||
$dataset->data[] = $value;
|
|
||||||
$obj->datasets[] = clone $dataset;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$ii = 0;
|
|
||||||
foreach ($row as $name => $value) {
|
|
||||||
if ($name != "time") {
|
|
||||||
$obj->datasets[$ii]->data[] = $value;
|
|
||||||
$ii++;
|
|
||||||
} else {
|
|
||||||
$obj->labels[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//header('Content-Type: application/json');
|
|
||||||
echo json_encode($obj);
|
|
||||||
//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]}]}';
|
|
||||||
@@ -2,15 +2,6 @@
|
|||||||
|
|
||||||
require_once("../helper.php");
|
require_once("../helper.php");
|
||||||
|
|
||||||
function getSSLPage($url) {
|
|
||||||
$curlSession = curl_init();
|
|
||||||
curl_setopt($curlSession, CURLOPT_URL, $url);
|
|
||||||
curl_setopt($curlSession, CURLOPT_BINARYTRANSFER, true);
|
|
||||||
curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
$jsonData = json_decode(curl_exec($curlSession),true);
|
|
||||||
curl_close($curlSession);
|
|
||||||
return $jsonData;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkLogin()) {
|
if (checkLogin()) {
|
||||||
$close = 0;
|
$close = 0;
|
||||||
@@ -48,13 +39,6 @@ if (checkLogin()) {
|
|||||||
}
|
}
|
||||||
if (!$close) {
|
if (!$close) {
|
||||||
echo <<<ENDE
|
echo <<<ENDE
|
||||||
<style>
|
|
||||||
input[type='range']::-webkit-slider-runnable-track {
|
|
||||||
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
|
|
||||||
background-size: var(--background-size, 0%) 100%;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<!--begin::Form-->
|
<!--begin::Form-->
|
||||||
<form id="heater_form">
|
<form id="heater_form">
|
||||||
<div class="col-sm-11">
|
<div class="col-sm-11">
|
||||||
|
|||||||
@@ -30,13 +30,6 @@ if (checkLogin()) {
|
|||||||
}
|
}
|
||||||
if (!$close) {
|
if (!$close) {
|
||||||
echo <<<ENDE
|
echo <<<ENDE
|
||||||
<style>
|
|
||||||
input[type='range']::-webkit-slider-runnable-track {
|
|
||||||
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
|
|
||||||
background-size: var(--background-size, 0%) 100%;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<!--begin::Form-->
|
<!--begin::Form-->
|
||||||
<form id="heater_form">
|
<form id="heater_form">
|
||||||
<div class="col-sm-11">
|
<div class="col-sm-11">
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 304 KiB |
|
Before Width: | Height: | Size: 347 KiB |
|
Before Width: | Height: | Size: 415 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 339 B |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,475 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="-100 -100 1600 950" width="100%" height="100%" id="realtimeSvgAni">
|
|
||||||
<defs>
|
|
||||||
<filter id="shadow" x="-0.5" y="-0.5" width="200%" height="200%">
|
|
||||||
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
|
|
||||||
<feMorphology in="offOut" result="offOut" operator="dilate" radius="0.7" />
|
|
||||||
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="0.5" />
|
|
||||||
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
|
|
||||||
</filter>
|
|
||||||
<filter id="shadowMiddle" x="-1.0" y="-1.0" width="300%" height="300%">
|
|
||||||
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
|
|
||||||
<feMorphology in="offOut" result="offOut" operator="dilate" radius="3" />
|
|
||||||
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="1" />
|
|
||||||
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
|
|
||||||
</filter>
|
|
||||||
<filter id="shadowBig" x="-1" y="-1" width="300%" height="300%">
|
|
||||||
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
|
|
||||||
<feMorphology in="offOut" result="offOut" operator="dilate" radius="3" />
|
|
||||||
<feGaussianBlur result="offOut" in="offOut" stdDeviation="2" />
|
|
||||||
<feBlend in="SourceGraphic" in2="offOut" mode="normal" />
|
|
||||||
</filter>
|
|
||||||
|
|
||||||
<g id="circGrid">
|
|
||||||
<line x2='27.7' y2='76.5' x1='-18.9' y1='61.4' style='stroke-width:4px' />
|
|
||||||
<line x2='16.5' y2='115.9' x1='-8.1' y1='120.6' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='34.5' y2='154.2' x1='15.2' y1='170.1' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='68.7' y2='179' x1='59.5' y1='202.3' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='110.7' y2='184.3' x1='113.8' y1='209.1' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='150' y2='168.8' x1='164.7' y1='189' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='176.9' y2='136.2' x1='199.5' y1='146.8' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='184.8' y2='94.7' x1='209.8' y1='93.1' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='171.8' y2='54.5' x1='192.9' y1='41.1' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='140.9' y2='25.5' x1='153' y1='3.6' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='100' y2='24' x1='100' y1='-24' style='stroke-width:4px' />
|
|
||||||
</g>
|
|
||||||
<g id="circGrid6kW">
|
|
||||||
<line x2='27.7' y2='76.5' x1='-18.9' y1='61.4' style='stroke-width:4px' />
|
|
||||||
<line x2='26.4' y2='142.5' x1='4.7' y1='155' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='82.3' y2='183.1' x1='77.1' y1='207.6' style='stroke:#555;stroke-width:4px;' />
|
|
||||||
<line x2='149.9' y2='168.8' x1='164.6' y1='189.0' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='184.5' y2='108.9' x1='209.4' y1='111.5' style='stroke:#555;stroke-width:4px;' />
|
|
||||||
<line x2='163.2' y2='43.1' x1='181.7' y1='26.4' style='stroke:#222;stroke-width:2;' />
|
|
||||||
<line x2='100' y2='24' x1='100' y1='-24' style='stroke-width:4px' />
|
|
||||||
</g>
|
|
||||||
<linearGradient id="gradient1" x1="0" x2="0" y1="0" y2="1">
|
|
||||||
<stop id="tmpH" offset="0%" stop-color="#2389BA" stop-opacity="0.7" />
|
|
||||||
<stop id="tmpM" offset="50%" stop-color="#2389BA" stop-opacity="0.7" />
|
|
||||||
<stop id="tmpL" offset="100%" stop-color="#2389BA" stop-opacity="0.7" />
|
|
||||||
</linearGradient>
|
|
||||||
<filter id="fillpartialEV" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
|
|
||||||
height="110%">
|
|
||||||
<feFlood flood-color="#1f5a66" />
|
|
||||||
<feComposite id="evChargeState" y="100%" operator="in" in2="SourceGraphic" />
|
|
||||||
<feComposite operator="over" in2="SourceGraphic" />
|
|
||||||
</filter>
|
|
||||||
<filter id="fillpartialHeat" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
|
|
||||||
height="110%">
|
|
||||||
<feFlood flood-color="#5E2B21" />
|
|
||||||
<feComposite id="heatChargeState" y="100%" operator="in" in2="SourceGraphic" />
|
|
||||||
<feComposite operator="over" in2="SourceGraphic" />
|
|
||||||
</filter>
|
|
||||||
<filter id="fillpartialBat" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
|
|
||||||
height="110%">
|
|
||||||
<feFlood flood-color="#25481C" />
|
|
||||||
<feComposite id="batChargeState" y="100%" operator="in" in2="SourceGraphic" />
|
|
||||||
<feComposite operator="over" in2="SourceGraphic" />
|
|
||||||
</filter>
|
|
||||||
<filter id="fillpartialWater" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
|
|
||||||
height="110%">
|
|
||||||
<feFlood flood-color="#182C43" />
|
|
||||||
<feComposite id="waterState" y="50%" operator="in" in2="SourceGraphic" />
|
|
||||||
<feComposite operator="over" in2="SourceGraphic" />
|
|
||||||
</filter>
|
|
||||||
|
|
||||||
<g id="heater" transform="rotate(-90),scale(0.07,0.07)">
|
|
||||||
<path
|
|
||||||
d="M485.924,134.508c14.381,0,26.076-11.669,26.076-26.017v-17.39c0-14.348-11.695-26.017-26.076-26.017H468.61v-8.737
|
|
||||||
c0-23.89-19.466-43.331-43.39-43.331s-43.39,19.441-43.39,43.331v8.737h-26.034v-8.737c0-23.89-19.466-43.331-43.39-43.331
|
|
||||||
c-23.924,0-43.39,19.441-43.39,43.331v8.737h-26.034v-8.737c0-23.89-19.466-43.331-43.39-43.331
|
|
||||||
c-23.924,0-43.39,19.441-43.39,43.331v8.737h-26.034v-8.737c0-23.89-19.466-43.331-43.39-43.331S43.39,32.458,43.39,56.348v8.737
|
|
||||||
H17.356V39.051H0v34.712v52.068v34.712h17.356v-26.034H43.39v269.017H8.678c-4.797,0-8.678,3.881-8.678,8.678v34.712
|
|
||||||
c0,4.797,3.881,8.678,8.678,8.678c4.797,0,8.678-3.881,8.678-8.678v-26.034H43.39v34.78c0,23.89,19.466,43.322,43.39,43.322
|
|
||||||
s43.39-19.432,43.39-43.322v-0.068h26.034v0.068c0,23.89,19.466,43.322,43.39,43.322c23.924,0,43.39-19.432,43.39-43.322v-0.068
|
|
||||||
h26.034v0.068c0,23.89,19.466,43.322,43.39,43.322c23.924,0,43.39-19.432,43.39-43.322v-0.068h26.034v0.068
|
|
||||||
c0,23.89,19.466,43.322,43.39,43.322s43.39-19.432,43.39-43.322v-0.068h17.314c14.381,0,26.076-11.669,26.076-26.017v-17.39
|
|
||||||
c0-14.347-11.695-26.017-26.076-26.017H468.61V134.508H485.924z M468.61,82.441h17.314c4.805,0,8.72,3.881,8.72,8.661v17.39
|
|
||||||
c0,4.78-3.915,8.661-8.72,8.661H468.61V82.441z M43.39,117.153H17.356V82.441H43.39V117.153z M112.814,73.763v52.068v269.017
|
|
||||||
v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966V125.831V73.763V56.348
|
|
||||||
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M156.203,438.237h-26.034v-34.712h26.034V438.237z
|
|
||||||
M156.203,386.169h-26.034V134.508h26.034V386.169z M156.203,117.153h-26.034V82.441h26.034V117.153z M225.627,73.763v52.068
|
|
||||||
v269.017v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966v-8.746v-52.068V125.831V73.763V56.348
|
|
||||||
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M269.017,438.237h-26.034v-34.712h26.034V438.237z
|
|
||||||
M269.017,386.169h-26.034V134.508h26.034V386.169z M269.017,117.153h-26.034V82.441h26.034V117.153z M338.441,73.763v52.068
|
|
||||||
v269.017v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966v-8.746v-52.068V125.831V73.763V56.348
|
|
||||||
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M381.831,438.237h-26.034v-34.712h26.034V438.237z
|
|
||||||
M381.831,386.169h-26.034V134.508h26.034V386.169z M381.831,117.153h-26.034V82.441h26.034V117.153z M451.254,73.763v52.068
|
|
||||||
v269.017v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966v-8.746v-52.068V125.831V73.763V56.348
|
|
||||||
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M485.924,403.525c4.805,0,8.72,3.881,8.72,8.661
|
|
||||||
v17.39c0,4.78-3.915,8.661-8.72,8.661H468.61v-34.712H485.924z" />
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<g id="gas">
|
|
||||||
<path fill-opacity="1" stroke-width="0.2" stroke-linejoin="round"
|
|
||||||
d="M 42.75,19L 42.75,31.4977C 44.5834,31.378 48.9184,32.7881 48.2917,49.0833C 49.0833,53.8333 54.625,53.8333 55.8125,47.5C 57,42.75 53.8333,42.75 52.25,28.5C 52.25,26.9167 52.25,22.1667 45.9167,19L 45.9167,17.4167C 52.25,17.4167 57,25.3333 57,26.9167C 57,28.5 55.4167,28.5 55.4167,28.5C 55.4167,28.5 55.8125,38 57.3958,39.5833C 58.9792,41.1667 58.5833,45.9167 58.5833,49.0833C 58.5833,52.25 53.8333,55.4167 52.25,55.4167C 50.6667,55.4167 45.9167,55.4167 45.9167,50.6667C 45.9167,46.3403 45.2599,36.7598 42.75,35.0854L 42.75,55.4167C 43.6244,55.4167 44.3333,56.1255 44.3333,57L 44.3333,60.1667L 19,60.1667L 19,57C 19,56.1255 19.7089,55.4167 20.5833,55.4167L 20.5833,19C 20.5833,17.2511 22.0011,15.8333 23.75,15.8333L 39.5833,15.8333C 41.3322,15.8333 42.75,17.2511 42.75,19 Z M 25.7291,33.2501L 37.6041,33.25C 38.4786,33.25 39.5833,32.1453 39.5833,31.2709L 39.5833,20.9792C 39.5833,20.1048 38.4786,19 37.6041,19L 25.7292,19C 24.8547,19 23.75,20.1048 23.75,20.9792L 23.75,31.2709C 23.75,32.1453 24.8547,33.2501 25.7291,33.2501 Z " />
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<g id="water">
|
|
||||||
<path
|
|
||||||
d="M283.897,92.846c-36.582-49.345-73.688-89.267-74.061-89.664C207.944,1.153,205.296,0,202.523,0
|
|
||||||
c-2.774,0-5.423,1.152-7.314,3.182c-0.371,0.397-37.478,40.319-74.06,89.664c-49.971,67.403-75.308,119.726-75.308,155.513
|
|
||||||
c0,86.396,70.287,156.688,156.682,156.688c86.396,0,156.683-70.29,156.683-156.688C359.206,212.572,333.868,160.25,283.897,92.846z
|
|
||||||
M218.171,354.342c-8.213,1.941-16.68,2.926-25.162,2.926c-60.294,0-109.347-49.055-109.347-109.35
|
|
||||||
c0-8.312,2.559-23.373,14.75-47.914c1.225-2.467,4.046-3.691,6.687-2.908c2.639,0.785,4.33,3.357,4.007,6.091
|
|
||||||
c-0.28,2.361-0.421,4.584-0.421,6.607c0,64.629,45.966,120.77,109.298,133.484c2.607,0.525,4.5,2.795,4.545,5.455
|
|
||||||
C222.575,351.396,220.761,353.729,218.171,354.342z" />
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<g id="voltage">
|
|
||||||
<path stroke="#212529" stroke-width="0.2px" d="M11.46,18V13.58H9.86L12.54,8v3.89h1.6Z" />
|
|
||||||
</g>
|
|
||||||
<path id="powerTextPath" d="M 100, 100 m -87, 0 a 87,87 0 1,1 174,0 a 87,87 0 1,1 -174,0"></path>
|
|
||||||
<path id="infoTextPath" d="M 100, 100 m -105, 0 a 105,105 0 1,0 210,0 a 105,105 0 1,0 -210,0"></path>
|
|
||||||
<g id="pvPlate" fill="none" stroke-width="4" stroke="#f7c000">
|
|
||||||
<rect width="70" height="40" x="0" y="0" rx="5" ry="5" />
|
|
||||||
</g>
|
|
||||||
<g id="ElementBG">
|
|
||||||
<path fill="#212529" stroke-width="1.5"
|
|
||||||
d="M 99.80277789465349 -12.999827891201505 A 113 113 0 1 0 100 -13" />
|
|
||||||
<path fill="none" stroke-width="4"
|
|
||||||
d="M 99.86386438745993 22.00011880076356 A 78 78 0 1 0 100 22" />
|
|
||||||
</g>
|
|
||||||
<g id="plugIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)" fill="#71afcd">
|
|
||||||
<path d="M15.21,6.73V2.63A.72.72,0,0,0,14.4,2h0a.71.71,0,0,0-.75.66V6.73Z" />
|
|
||||||
<path d="M10.39,6.73V2.62A.7.7,0,0,0,9.6,2h0a.73.73,0,0,0-.78.66V6.73Z" />
|
|
||||||
<path
|
|
||||||
d="M6.71,7.23C6.37,7.22,6,8,6,8.8V10c0,2.48.57,4.62,1.63,5.28S9,16,10.35,16.77V22h3.3V16.77c1.38-.8,1.66-.85,2.72-1.51S18,12.46,18,10V8.8c0-.78-.37-1.58-.71-1.57Z" />
|
|
||||||
</g>
|
|
||||||
<g id="ogIcon" filter="url(#shadow)" transform="translate(52,45),scale(4,4)">
|
|
||||||
<polygon fill="#70CCBB"
|
|
||||||
points="12.01 1.5 2 10.32 3.11 10.32 3.11 21.5 5.12 21.5 5.12 10.32 12 4.13 18.89 10.32 18.89 21.5 20.89 21.5 20.89 10.32 22 10.32 12.01 1.5" />
|
|
||||||
<path fill="#70CCBB"
|
|
||||||
d="M8.55,12.65v3.49a2.12,2.12,0,0,0,2.13,2.09h.67s0,3.23,0,3.27h1.49s0-3.24,0-3.28h.77a1.82,1.82,0,0,0,1.8-1.85l0-3.73" />
|
|
||||||
<path fill="#70CCBB" d="M10.76,11.41v-1.3c0-.45-.17-.67-.52-.68s-.54.22-.54.69v1.67h1.06Z" />
|
|
||||||
<path fill="#70CCBB"
|
|
||||||
d="M14.3,11.41c0-.44,0-.88,0-1.3s-.17-.67-.51-.68-.55.22-.55.69v1.67H14.3Z" />
|
|
||||||
<path fill="#212529"
|
|
||||||
d="M9.86,13.86h4.28a0,0,0,0,1,0,0v2a1,1,0,0,1-1,1H10.86a1,1,0,0,1-1-1v-2A0,0,0,0,1,9.86,13.86Z" />
|
|
||||||
</g>
|
|
||||||
<g id="heatIcon" filter="url(#shadow)" transform="translate(52,70),scale(4,4)" fill="#C2614E">
|
|
||||||
<path clip-path="M-22 2.24h42V22h-42z"
|
|
||||||
d="M16.543 8.028c-.023 1.503-.523 3.538-2.867 4.327.734-1.746.846-3.417.326-4.979-.695-2.097-3.014-3.735-4.557-4.627-.527-.306-1.203.074-1.193.683.02 1.112-.318 2.737-1.959 4.378C4.107 9.994 3 12.251 3 14.517 3 17.362 5 21 9 21c-4.041-4.041-1-7.483-1-7.483C8.846 19.431 12.988 21 15 21c1.711 0 5-1.25 5-6.448 0-3.133-1.332-5.511-2.385-6.899-.347-.458-1.064-.198-1.072.375" />
|
|
||||||
</g>
|
|
||||||
<g id="ugIcon" filter="url(#shadow)" transform="translate(52,50),scale(4,4)">
|
|
||||||
<rect stroke="#70CC9C" stroke-width="2" fill="none" x="3" y="3" width="18" height="18" rx="2" />
|
|
||||||
<path fill="#70CC9C"
|
|
||||||
d="M8.55,9.2v3.47a2.11,2.11,0,0,0,2.13,2.08h.67s0,3.22,0,3.26h1.49s0-3.22,0-3.26h.77a1.81,1.81,0,0,0,1.8-1.84l0-3.71" />
|
|
||||||
<path fill="#70CC9C" d="M10.76,8V6.67c0-.45-.17-.66-.52-.67s-.54.22-.54.68V8.34h1.06Z" />
|
|
||||||
<path fill="#70CC9C" d="M14.3,8c0-.44,0-.87,0-1.3S14.12,6,13.78,6s-.55.22-.55.68V8.34H14.3Z" />
|
|
||||||
<path fill="#212529"
|
|
||||||
d="M9.86,10.41h4.28a0,0,0,0,1,0,0v2a1,1,0,0,1-1,1H10.86a1,1,0,0,1-1-1v-2A0,0,0,0,1,9.86,10.41Z" />
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<g id="carIcon" filter="url(#shadow)" transform="translate(45,45),scale(4.8,4.8)"
|
|
||||||
fill="#212529" stroke-linecap="round">
|
|
||||||
<path d="M16.22,15.37l-9.3-.16L3,15,.88,14.47.75,10.39A2.78,2.78,0,0,1,1.31,9.2L2.55,7.63" />
|
|
||||||
<path
|
|
||||||
d="M.78,7.46,7,7l.87,0L11.37,7a5.57,5.57,0,0,1,1.06.23,9.43,9.43,0,0,1,2.16,1L17.23,9.9l4.22.7a1.73,1.73,0,0,1,1.21.93l.26.49a2.84,2.84,0,0,1,.32,1.6l0,.23A1.52,1.52,0,0,1,22.53,15h0a1.53,1.53,0,0,1-.56.21l-.89.15H15.59" />
|
|
||||||
<path fill="#888888" stroke="none"
|
|
||||||
d="M16.06,11c-1.85.11-3.7.14-5.55.16a13.36,13.36,0,0,1-2.82,0,2.62,2.62,0,0,1-.87-.4,1.28,1.28,0,0,1-.53-1.05,1.4,1.4,0,0,1,.09-.51,2.67,2.67,0,0,1,.22-.35,2.79,2.79,0,0,1,.5-.58s.09,0,.11,0a.06.06,0,0,1,0,.05h0c0,.25,0,.49,0,.71s0,.23,0,.31a.75.75,0,0,0,.08.18c.07.09.17.14.17.08a1.81,1.81,0,0,0,.43.05,14.41,14.41,0,0,1,2.68.33c1.82.26,3.64.53,5.46.88a.08.08,0,0,1,.06.09A.07.07,0,0,1,16.06,11Z" />
|
|
||||||
<circle cx="4.94" cy="15.08" r="1.98" />
|
|
||||||
<circle cx="19.19" cy="15.08" r="1.98" />
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<g id="plugCordIcon" transform="scale(0.08,0.08),rotate(340),translate(-350,1200)">
|
|
||||||
<path
|
|
||||||
d="M489.8,280.92c0-13.9-11.3-25.2-25.2-25.2h-74.1c-62.1,0-112.4,50.2-112.7,112.2c-0.1,32.3-23,61-55,65
|
|
||||||
c-38.4,4.8-71.2-25.2-71.2-62.6v-56.4c57.6-11.7,101-62.6,101-123.7v-64c0-9.1-7.3-16.4-16.4-16.4h-31.3v-79.1
|
|
||||||
c0-12.4-9-23.4-21.3-24.6c-14.1-1.4-26,9.7-26,23.6v80.1H95.2v-79.1c0-12.4-9-23.4-21.4-24.6c-14.1-1.3-26,9.7-26,23.6v80.1H16.4
|
|
||||||
c-9.1,0-16.4,7.3-16.4,16.4v64c0,61.1,43.4,112,101,123.7v53.5c0,61.5,47.7,114,109.2,116.3c64.6,2.4,118-49.4,118-113.5v-0.9
|
|
||||||
c0-34.9,28.3-63.1,63.1-63.1h73.2C478.5,306.12,489.8,294.82,489.8,280.92L489.8,280.92z" />
|
|
||||||
</g>
|
|
||||||
<g id="lockIcon" transform="translate(80,130),scale(0.11,0.11)" style="">
|
|
||||||
<path
|
|
||||||
d="M65,330h200c8.284,0,15-6.716,15-15V145c0-8.284-6.716-15-15-15h-15V85c0-46.869-38.131-85-85-85
|
|
||||||
S80,38.131,80,85v45H65c-8.284,0-15,6.716-15,15v170C50,323.284,56.716,330,65,330z M207.481,219.356l-42.5,42.5
|
|
||||||
c-2.929,2.929-6.768,4.394-10.606,4.394s-7.678-1.465-10.606-4.394l-21.25-21.25c-5.858-5.858-5.858-15.354,0-21.213
|
|
||||||
c5.857-5.858,15.355-5.858,21.213,0l10.644,10.643l31.894-31.893c5.857-5.858,15.355-5.858,21.213,0
|
|
||||||
C213.34,204.002,213.34,213.498,207.481,219.356z M110,85c0-30.327,24.673-55,55-55s55,24.673,55,55v45H110V85z"
|
|
||||||
style="stroke-width:15px;stroke:rgb(30,30,40);fill:#778;" />
|
|
||||||
</g>
|
|
||||||
<g filter="url(#shadow)" id="clock" style="fill:#cc0;"
|
|
||||||
transform="translate(80,32),scale(0.07,0.07)">
|
|
||||||
<path
|
|
||||||
d="m256,51.8c-112.6,0-204.2,91.6-204.2,204.2s91.6,204.2 204.2,204.2 204.2-91.6 204.2-204.2-91.6-204.2-204.2-204.2v-1.42109e-14zm0,449.2c-135.1,0-245-109.9-245-245s109.9-245 245-245 245,109.9 245,245-109.9,245-245,245z" />
|
|
||||||
<path
|
|
||||||
d="m327.9,276.4h-71.9c-11.3,0-20.4-9.1-20.4-20.4v-132.2c0-11.3 9.1-20.4 20.4-20.4 11.3,0 20.4,9.1 20.4,20.4v111.8h51.5c11.3,0 20.4,9.1 20.4,20.4s-9.1,20.4-20.4,20.4z" />
|
|
||||||
</g>
|
|
||||||
<g id="sunIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)"
|
|
||||||
style="stroke:#f7c000;stroke-width:2;stroke-linecap:round;">
|
|
||||||
<path id="Pfad_7565" data-name="Pfad 7565" fill="#f7c002" stroke-width="0"
|
|
||||||
d="M12,8a4,4,0,1,0,4,4A4,4,0,0,0,12,8Z" />
|
|
||||||
<line x1="12" y1="3" x2="12" y2="5" />
|
|
||||||
<line x1="12" y1="19" x2="12" y2="21" />
|
|
||||||
<line x1="19" y1="12" x2="21" y2="12" />
|
|
||||||
<line x1="3" y1="12" x2="5" y2="12" />
|
|
||||||
<line x1="5.7" y1="18.5" x2="7" y2="17" />
|
|
||||||
<line x1="5.7" y1="5.7" x2="7" y2="7" />
|
|
||||||
<line x1="18.5" y1="18.5" x2="16.7" y2="17" />
|
|
||||||
<line x1="18.5" y1="5.7" x2="16.7" y2="7" />
|
|
||||||
</g>
|
|
||||||
<g id="battIcon" filter="url(#shadow)" transform="translate(30,25),scale(6,6)">
|
|
||||||
<g>
|
|
||||||
<rect fill="#6cbe58" x="9.25" y="3" width="5.5" height="4" rx="1" ry="1" />
|
|
||||||
<path fill="#6cbe58"
|
|
||||||
d="M16.28,5H7.72A1.21,1.21,0,0,0,6.5,6.2V19.73A1.28,1.28,0,0,0,7.72,21h8.56a1.28,1.28,0,0,0,1.22-1.27V6.2A1.21,1.21,0,0,0,16.28,5Z" />
|
|
||||||
<rect id="discharged" fill="#212529" rx="1" ry="1" x="8" y="6.5" width="8"
|
|
||||||
height="13" />
|
|
||||||
<use id="charge" fill="#cccc00" href="#voltage" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g id="gridIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)">
|
|
||||||
<path fill="#808090"
|
|
||||||
d="M13.38,8.54V6.63H18.3V8.06h.95V5.7l-6.35-1L12,2l-1,2.8-6.25.9V8.07H5.6V6.63h4.84V8.54l-7.59,1.9v2.84H3.8V11.76H9.87L6.93,22H9.11l.57-2.46h4.59L14.8,22h2.27L14.13,11.76H20.2v1.52h.95V10.44Zm-3.32,8.81L12,11.11l1.91,6.24Z" />
|
|
||||||
</g>
|
|
||||||
<g id="inverterIcon" filter="url(#shadowBig)" fill="#b2b2b2" stroke-width="2px" stroke="#666"
|
|
||||||
transform="translate(43,43),scale(1.6,1.6)">
|
|
||||||
<rect stroke-width="2px" x="5.65" y="3" width="58.7" height="64" rx="6.8" />
|
|
||||||
<circle cx="35.03" cy="29.61" r="11" />
|
|
||||||
<circle cx="15" cy="40" r="4" />
|
|
||||||
<path
|
|
||||||
d="M40.19,52H36.73a2,2,0,0,0-3.46,0H29.81a1.08,1.08,0,1,0,0,2.15h3.46a2,2,0,0,0,3.46,0h3.46a1.08,1.08,0,1,0,0-2.15Z" />
|
|
||||||
<path fill="#e2001a"
|
|
||||||
d="M34.89,61.87c-3.24,0-5.87-.73-5.87-1.62s2.63-1.64,5.87-1.64,5.87.74,5.87,1.64S38.13,61.87,34.89,61.87Z" />
|
|
||||||
<line x1="5.07" y1="53.08" x2="28.73" y2="53.08" />
|
|
||||||
<line x1="41.27" y1="53.08" x2="64.93" y2="53.08" />
|
|
||||||
</g>
|
|
||||||
<g id="northIcon" fill="#808090">
|
|
||||||
<path
|
|
||||||
d="M42.066 0v20h3.752V6.957L53.881 20h4.053V0h-3.752v13.355L45.996 0zm5.57 26.688l-25.77 69.949c-.823 2.238 1.658 4.248 3.677 2.978L50 84.195l24.455 15.42c2.02 1.273 4.504-.738 3.68-2.978l-25.79-70c-.472-1.096-1.283-1.632-2.384-1.635c-1.1-.003-2.017.856-2.324 1.686zm-.136 14.83V79.86L29.1 91.463z"></path>
|
|
||||||
</g>
|
|
||||||
<g filter="url(#shadow)" id="ecoIcon" transform="translate(60,12)">
|
|
||||||
<path style="stroke:#6cbe58;fill:rgb(30,30,40);" stroke-width="3" stroke-linejoin="round"
|
|
||||||
d="M 57,22.1667C 49.0833,28.5 52.25,31.6667 50.6667,36.4167C 49.0833,41.1667 50.6667,42.75 44.3333,47.5C 36.2227,53.583 29.2917,49.875 29.2917,49.875C 27.7083,51.4583 21.7708,54.2292 21.7708,54.2292L 20.0143,50.7285C 26.3476,49.1452 27.7083,47.1042 27.7083,47.1042C 26.125,43.9375 23.75,38 28.5,30.0833C 33.25,22.1667 57,22.1667 57,22.1667 Z M 30.0833,44.3333L 31.6667,45.9167C 31.6667,45.9167 34.8333,44.3333 36.4167,39.5833C 38,34.8333 45.9167,26.9167 45.9167,26.9167C 42.75,28.5 36.4167,34.8333 34.8333,39.5833C 33.25,44.3333 30.0833,44.3333 30.0833,44.3333 Z " />
|
|
||||||
</g>
|
|
||||||
<g filter="url(#shadow)" id="alertIcon" fill="#aa0" transform="translate(34,28),scale(2.2,2.2)">
|
|
||||||
<path
|
|
||||||
d="M214.413,746a4.455,4.455,0,0,1-3.84-2.166,4.249,4.249,0,0,1,0-4.334l25.572-43.331a4.483,4.483,0,0,1,7.679,0L269.4,739.5a4.249,4.249,0,0,1,0,4.334,4.452,4.452,0,0,1-3.84,2.166H214.413ZM240,706a4,4,0,0,0-4,4v16a4,4,0,0,0,8,0V710A4,4,0,0,0,240,706Zm0,36a4,4,0,1,0-4-4A4,4,0,0,0,240,742Z"
|
|
||||||
id="attention" transform="translate(-209.969 -694)" />
|
|
||||||
</g>
|
|
||||||
|
|
||||||
</defs>
|
|
||||||
<g id="pvDetail" opacity="1" transform="scale(1,1)">
|
|
||||||
|
|
||||||
<g id="pvInfo" transform="translate(80,30)" class="clickable" onclick="displayOverlay('realtime')">
|
|
||||||
<!--<g
|
|
||||||
filter="url(#glow)">-->
|
|
||||||
<use href="#ElementBG" stroke="#574400" />
|
|
||||||
<use href="#sunIcon" />
|
|
||||||
<path id="pvArc" fill="none" stroke="#f7c000" stroke-width="30" />
|
|
||||||
<path id="pv2Arc" fill="none" stroke="#f78d00" stroke-width="30" />
|
|
||||||
<path id="pv3Arc" fill="none" stroke="#f72300" stroke-width="30" />
|
|
||||||
<use href="#circGrid" style="stroke:#574400;" />
|
|
||||||
<!--</g>-->
|
|
||||||
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
|
||||||
<textPath id="pvText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
|
|
||||||
<textPath id="pv3txt" href="#infoTextPath" startOffset="12%">--.-- kW</textPath>
|
|
||||||
<textPath id="pv2txt" href="#infoTextPath" startOffset="35%">--.-- kW</textPath>
|
|
||||||
<textPath id="pv1txt" href="#infoTextPath" startOffset="55%">--W</textPath>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
<animate begin="openDetails.begin" attributetype="CSS" attributeName="opacity" from="0"
|
|
||||||
to="1.0"
|
|
||||||
dur="0.7s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
|
|
||||||
fill="freeze" />
|
|
||||||
<animateTransform attributeName="transform"
|
|
||||||
type="scale"
|
|
||||||
from="0.1,0.1"
|
|
||||||
to="1,1"
|
|
||||||
begin="openDetails.begin"
|
|
||||||
dur="0.3s" repeatCount="1" fill="freeze" />
|
|
||||||
<animate begin="closeDetails.click" attributetype="CSS" attributeName="opacity" from="1.0"
|
|
||||||
to="0"
|
|
||||||
dur="0.4s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
|
|
||||||
fill="freeze" />
|
|
||||||
<animateTransform attributeName="transform"
|
|
||||||
type="scale"
|
|
||||||
from="1,1"
|
|
||||||
to="0.1,0.1"
|
|
||||||
begin="closeDetails.click"
|
|
||||||
dur="0.7s" repeatCount="1" fill="freeze" />
|
|
||||||
<use href="#northIcon" transform="translate(1200,10),rotate(10)" />
|
|
||||||
<polygon points="370 0, 1300 0, 1300 700, 0 700, 0 250, 370 250" fill="rgb(24, 27, 31)" />
|
|
||||||
<polygon points="560,80 720,80 720,300 1160,300 1160,370 560,370" stroke-linejoin="round"
|
|
||||||
fill="#f7c002" stroke-width="30" stroke="#f7c002" opacity="0.1" />
|
|
||||||
<use href="#pvPlate" transform="translate(600,80), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(600,150), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(600,220), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(600,290), rotate(90)" />
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(640,80), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(640,150), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(640,220), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(640,290), rotate(90)" />
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(680,80), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(680,150), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(680,220), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(680,290), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(720,80), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(720,150), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(720,220), rotate(90)" />
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(790,290)" />
|
|
||||||
<use href="#pvPlate" transform="translate(720,330)" />
|
|
||||||
<use href="#pvPlate" transform="translate(790,330)" />
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(870,290)" />
|
|
||||||
<use href="#pvPlate" transform="translate(870,330)" />
|
|
||||||
<use href="#pvPlate" transform="translate(940,330)" />
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(1160,300), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(1120,300), rotate(90)" />
|
|
||||||
<use href="#pvPlate" transform="translate(1080,300), rotate(90)" />
|
|
||||||
|
|
||||||
|
|
||||||
<text id="det_pv0P" filter="url(#shadowBig)" class="infoTextClass" dx="55" dy="30"
|
|
||||||
transform="translate(560, 150), scale(1.5,1.5)">-.-- kW</text>
|
|
||||||
<polygon points="980,60 1160,60 1160,265 980,265" stroke-linejoin="round" fill="#F76D00"
|
|
||||||
stroke-width="30" stroke="#F76D00" opacity="0.1" />
|
|
||||||
<use href="#pvPlate" transform="translate(1160,200), rotate(90), scale(1,1.125)" />
|
|
||||||
<use href="#pvPlate" transform="translate(1115,200), rotate(90), scale(1,1.125)" />
|
|
||||||
<use href="#pvPlate" transform="translate(1070,200), rotate(90), scale(1,1.125)" />
|
|
||||||
<use href="#pvPlate" transform="translate(1160,130), rotate(90), scale(1,1.125)" />
|
|
||||||
<use href="#pvPlate" transform="translate(1115,130), rotate(90), scale(1,1.125)" />
|
|
||||||
<use href="#pvPlate" transform="translate(1070,130), rotate(90), scale(1,1.125)" />
|
|
||||||
<use href="#pvPlate" transform="translate(1025,130), rotate(90), scale(1,1.125)" />
|
|
||||||
<use href="#pvPlate" transform="translate(1160,60), rotate(90), scale(1,1.125)" />
|
|
||||||
<use href="#pvPlate" transform="translate(1115,60), rotate(90), scale(1,1.125)" />
|
|
||||||
<use href="#pvPlate" transform="translate(1070,60), rotate(90), scale(1,1.125)" />
|
|
||||||
<text id="det_pv1P" filter="url(#shadowBig)" class="infoTextClass" dx="55" dy="30"
|
|
||||||
transform="translate(990, 140), scale(1.5,1.5)">-.-- kW</text>
|
|
||||||
|
|
||||||
<use href="#pvPlate" x="200" y="680" />
|
|
||||||
<text id="det_pv33P" filter="url(#shadowMiddle)" class="infoTextClass" x="200" y="680"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#19</text>
|
|
||||||
<use href="#pvPlate" x="380" y="550" />
|
|
||||||
<text id="det_pv32P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="550"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#19</text>
|
|
||||||
<use href="#pvPlate" x="380" y="590" />
|
|
||||||
<text id="det_pv31P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="590"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#18</text>
|
|
||||||
<use href="#pvPlate" x="380" y="630" />
|
|
||||||
<text id="det_pv30P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="630"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#17</text>
|
|
||||||
<use href="#pvPlate" x="310" y="510" />
|
|
||||||
<text id="det_pv29P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="510"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#16</text>
|
|
||||||
<use href="#pvPlate" x="310" y="550" />
|
|
||||||
<text id="det_pv28P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="550"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#15</text>
|
|
||||||
<use href="#pvPlate" x="310" y="590" />
|
|
||||||
<text id="det_pv27P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="590"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#14</text>
|
|
||||||
<use href="#pvPlate" x="310" y="630" />
|
|
||||||
<text id="det_pv26P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="630"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#13</text>
|
|
||||||
<use href="#pvPlate" x="240" y="510" />
|
|
||||||
<text id="det_pv25P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="510"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#12</text>
|
|
||||||
<use href="#pvPlate" x="240" y="550" />
|
|
||||||
<text id="det_pv24P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="550"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#11</text>
|
|
||||||
<use href="#pvPlate" x="240" y="590" />
|
|
||||||
<text id="det_pv23P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="590"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#10</text>
|
|
||||||
<use href="#pvPlate" x="240" y="630" />
|
|
||||||
<text id="det_pv22P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="630"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#9</text>
|
|
||||||
<use href="#pvPlate" x="170" y="510" />
|
|
||||||
<text id="det_pv21P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="510"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#8</text>
|
|
||||||
<use href="#pvPlate" x="170" y="550" />
|
|
||||||
<text id="det_pv20P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="550"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#7</text>
|
|
||||||
<use href="#pvPlate" x="170" y="590" />
|
|
||||||
<text id="det_pv19P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="590"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#6</text>
|
|
||||||
<use href="#pvPlate" x="170" y="630" />
|
|
||||||
<text id="det_pv18P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="630"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#5</text>
|
|
||||||
<use href="#pvPlate" x="100" y="510" />
|
|
||||||
<text id="det_pv14P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="510"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#1</text>
|
|
||||||
<use href="#pvPlate" x="100" y="550" />
|
|
||||||
<text id="det_pv15P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="550"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#2</text>
|
|
||||||
<use href="#pvPlate" x="100" y="590" />
|
|
||||||
<text id="det_pv16P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="590"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#3</text>
|
|
||||||
<use href="#pvPlate" x="100" y="630" />
|
|
||||||
<text id="det_pv17P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="630"
|
|
||||||
dx="36"
|
|
||||||
dy="26">#4</text>
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(600,500)" />
|
|
||||||
<text id="det_pv13P" filter="url(#shadowMiddle)" class="infoTextClass" x="600" y="500"
|
|
||||||
dx="36"
|
|
||||||
dy="26">- W</text>
|
|
||||||
<use href="#pvPlate" transform="translate(500,500)" />
|
|
||||||
<text id="det_pv12P" filter="url(#shadowMiddle)" class="infoTextClass" x="500" y="500"
|
|
||||||
dx="36"
|
|
||||||
dy="26">- W</text>
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(460,120), rotate(-90)" />
|
|
||||||
<text id="det_pv5P" filter="url(#shadowMiddle)" class="infoTextClass"
|
|
||||||
transform="translate(460,120), rotate(-90)" dx="36" dy="26">- W</text>
|
|
||||||
<use href="#pvPlate" transform="translate(460,190), rotate(-90)" />
|
|
||||||
<text id="det_pv4P" filter="url(#shadowMiddle)" class="infoTextClass"
|
|
||||||
transform="translate(460,190), rotate(-90)" dx="36" dy="26">- W</text>
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(460,270), rotate(-90)" />
|
|
||||||
<text id="det_pv9P" filter="url(#shadowMiddle)" class="infoTextClass"
|
|
||||||
transform="translate(460,270), rotate(-90)" dx="36" dy="26">- W</text>
|
|
||||||
<use href="#pvPlate" transform="translate(460,340), rotate(-90)" />
|
|
||||||
<text id="det_pv8P" filter="url(#shadowMiddle)" class="infoTextClass"
|
|
||||||
transform="translate(460,340), rotate(-90)" dx="36" dy="26">- W</text>
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(460,420), rotate(-90)" />
|
|
||||||
<text id="det_pv11P" filter="url(#shadowMiddle)" class="infoTextClass"
|
|
||||||
transform="translate(460,420), rotate(-90)" dx="36" dy="26">- W</text>
|
|
||||||
<use href="#pvPlate" transform="translate(460,490), rotate(-90)" />
|
|
||||||
<text id="det_pv10P" filter="url(#shadowMiddle)" class="infoTextClass"
|
|
||||||
transform="translate(460,490), rotate(-90)" dx="36" dy="26">- W</text>
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(400,120), rotate(-90)" />
|
|
||||||
<text id="det_pv7P" filter="url(#shadowMiddle)" class="infoTextClass"
|
|
||||||
transform="translate(400,120), rotate(-90)" dx="36" dy="26">- W</text>
|
|
||||||
<use href="#pvPlate" transform="translate(400,190), rotate(-90)" />
|
|
||||||
<text id="det_pv6P" filter="url(#shadowMiddle)" class="infoTextClass"
|
|
||||||
transform="translate(400,190), rotate(-90)" dx="36" dy="26">- W</text>
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(400,270), rotate(-90)" />
|
|
||||||
<text id="det_pv3P" filter="url(#shadowMiddle)" class="infoTextClass"
|
|
||||||
transform="translate(400,270), rotate(-90)" dx="36" dy="26">- W</text>
|
|
||||||
|
|
||||||
<use href="#pvPlate" transform="translate(400,340), rotate(-90)" />
|
|
||||||
<text id="det_pv2P" filter="url(#shadowMiddle)" class="infoTextClass"
|
|
||||||
transform="translate(400,340), rotate(-90)" dx="36" dy="26">- W</text>
|
|
||||||
|
|
||||||
|
|
||||||
<text id="invList" filter="url(#shadowMiddle)" class="tooltipTextClass"
|
|
||||||
transform="translate(80,255)"></text>
|
|
||||||
<rect width="305" height="210" x="70" y="250" rx="5" ry="5" fill="none" stroke-width="4px"
|
|
||||||
stroke="#f7c000" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 33 KiB |
@@ -1,21 +1,30 @@
|
|||||||
<style>
|
<style>
|
||||||
.stream{
|
/* Fluss-Animation als transform statt stroke-dashoffset.
|
||||||
animation: stream 2s steps(40) infinite;
|
stroke-dashoffset ist nicht kompositierbar - jede Stufe kostete einen
|
||||||
|
Neuzeichenvorgang auf dem Hauptthread. Ein transform kann der Compositor
|
||||||
|
dagegen selbst verschieben.
|
||||||
|
Die Punkte laufen eine Periode (111 Einheiten) weit, danach steht der
|
||||||
|
naechste an derselben Stelle - der Zyklus schliesst nahtlos.
|
||||||
|
--dx/--dy stehen pro Linie im style-Attribut, --w setzt setFlowWidth().
|
||||||
|
steps(40) = 20 Bewegungen pro Sekunde, wie in der urspruenglichen
|
||||||
|
Fassung. Das deckelt die Neuzeichnungen fuer den Fall, dass der Browser
|
||||||
|
das transform doch nicht kompositiert; auf dem Compositor kostet die
|
||||||
|
Stufung nichts. Fuer volle Fluessigkeit: linear statt steps(40). */
|
||||||
|
.stream, .stream-rev {
|
||||||
|
animation: flow 2s steps(40) infinite;
|
||||||
}
|
}
|
||||||
@keyframes stream {
|
.stream-rev {
|
||||||
100%{
|
animation-direction: reverse;
|
||||||
stroke-dashoffset: -110;
|
|
||||||
}
|
}
|
||||||
}
|
@keyframes flow {
|
||||||
.stream-rev{
|
to { transform: translate(var(--dx), var(--dy)); }
|
||||||
animation: stream-rev 2s steps(40) infinite;
|
|
||||||
}
|
}
|
||||||
@keyframes stream-rev {
|
.stream circle, .stream-rev circle {
|
||||||
100%{
|
r: calc(var(--w, 0px) / 2);
|
||||||
stroke-dashoffset: 110;
|
fill: gray;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.powerTextClass {
|
.powerTextClass {
|
||||||
font-size: 27px;
|
font-size: 27px;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
text-anchor: middle;
|
text-anchor: middle;
|
||||||
@@ -63,6 +72,16 @@
|
|||||||
<feMergeNode in="SourceGraphic" />
|
<feMergeNode in="SourceGraphic" />
|
||||||
</feMerge>
|
</feMerge>
|
||||||
</filter>
|
</filter>
|
||||||
|
<clipPath id="clip_consOGani"><rect x="-30" y="-30" width="404.4" height="60" transform="translate(770.0,380.0) rotate(-64.1790)"/></clipPath>
|
||||||
|
<clipPath id="clip_consAni"><rect x="-30" y="-30" width="400.0" height="60" transform="translate(430.0,380.0) rotate(0.0000)"/></clipPath>
|
||||||
|
<clipPath id="clip_consEGani"><rect x="-30" y="-30" width="386.5" height="60" transform="translate(770.0,380.0) rotate(62.6501)"/></clipPath>
|
||||||
|
<clipPath id="clip_consUGani"><rect x="-30" y="-30" width="396.2" height="60" transform="translate(770.0,380.0) rotate(120.3791)"/></clipPath>
|
||||||
|
<clipPath id="clip_consHeatAni"><rect x="-30" y="-30" width="410.0" height="60" transform="translate(770.0,380.0) rotate(0.0000)"/></clipPath>
|
||||||
|
<clipPath id="clip_consEVani"><rect x="-30" y="-30" width="360.0" height="60" transform="translate(920.0,670.0) rotate(0.0000)"/></clipPath>
|
||||||
|
<clipPath id="clip_consEVOGani"><rect x="-30" y="-30" width="360.0" height="60" transform="translate(920.0,70.0) rotate(0.0000)"/></clipPath>
|
||||||
|
<clipPath id="clip_consGridani"><rect x="-30" y="-30" width="390.0" height="60" transform="translate(100.0,380.0) rotate(0.0000)"/></clipPath>
|
||||||
|
<clipPath id="clip_pvani"><rect x="-30" y="-30" width="413.6" height="60" transform="translate(180.0,130.0) rotate(45.0000)"/></clipPath>
|
||||||
|
<clipPath id="clip_battani"><rect x="-30" y="-30" width="413.6" height="60" transform="translate(180.0,630.0) rotate(-45.0000)"/></clipPath>
|
||||||
</defs>
|
</defs>
|
||||||
<g opacity="0">
|
<g opacity="0">
|
||||||
<animate begin="lastInitAni.end" attributetype="CSS" attributeName="opacity" from="0.0" to="1.0"
|
<animate begin="lastInitAni.end" attributetype="CSS" attributeName="opacity" from="0.0" to="1.0"
|
||||||
@@ -81,44 +100,34 @@
|
|||||||
+500 -300 (center +90 in x und y)
|
+500 -300 (center +90 in x und y)
|
||||||
-->
|
-->
|
||||||
<line x1="770" y1="380" x2="920" y2="70" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
<line x1="770" y1="380" x2="920" y2="70" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
<line id="consOGani" class="stream" x1="770" y1="380" x2="920" y2="70" stroke-linecap="round"
|
<g clip-path="url(#clip_consOGani)"><g id="consOGani" class="stream" style="--dx:48.347px;--dy:-99.918px"><circle cx="721.7" cy="479.9"/><circle cx="770.0" cy="380.0"/><circle cx="818.3" cy="280.1"/><circle cx="866.7" cy="180.2"/><circle cx="915.0" cy="80.2"/><circle cx="963.4" cy="-19.7"/></g></g>
|
||||||
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
|
||||||
|
|
||||||
<line x1="430" y1="380" x2="770" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
<line x1="430" y1="380" x2="770" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
<line id="consAni" class="stream" x1="430" y1="380" x2="770" y2="380" stroke-linecap="round"
|
<g clip-path="url(#clip_consAni)"><g id="consAni" class="stream" style="--dx:111.000px;--dy:0.000px"><circle cx="319.0" cy="380.0"/><circle cx="430.0" cy="380.0"/><circle cx="541.0" cy="380.0"/><circle cx="652.0" cy="380.0"/><circle cx="763.0" cy="380.0"/><circle cx="874.0" cy="380.0"/></g></g>
|
||||||
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
|
||||||
|
|
||||||
<line x1="770" y1="380" x2="920" y2="670" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
<line x1="770" y1="380" x2="920" y2="670" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
<line id="consEGani" class="stream" x1="770" y1="380" x2="920" y2="670" stroke-linecap="round"
|
<g clip-path="url(#clip_consEGani)"><g id="consEGani" class="stream" style="--dx:50.996px;--dy:98.592px"><circle cx="719.0" cy="281.4"/><circle cx="770.0" cy="380.0"/><circle cx="821.0" cy="478.6"/><circle cx="872.0" cy="577.2"/><circle cx="923.0" cy="675.8"/></g></g>
|
||||||
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
|
||||||
|
|
||||||
<line x1="770" y1="380" x2="600" y2="670" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
<line x1="770" y1="380" x2="600" y2="670" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
<line id="consUGani" class="stream" x1="770" y1="380" x2="600" y2="670" stroke-linecap="round"
|
<g clip-path="url(#clip_consUGani)"><g id="consUGani" class="stream" style="--dx:-56.135px;--dy:95.759px"><circle cx="826.1" cy="284.2"/><circle cx="770.0" cy="380.0"/><circle cx="713.9" cy="475.8"/><circle cx="657.7" cy="571.5"/><circle cx="601.6" cy="667.3"/><circle cx="545.5" cy="763.0"/></g></g>
|
||||||
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
|
||||||
|
|
||||||
<line x1="770" y1="380" x2="1120" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
<line x1="770" y1="380" x2="1120" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
<line id="consHeatAni" class="stream" x1="770" y1="380" x2="1120" y2="380" stroke-linecap="round"
|
<g clip-path="url(#clip_consHeatAni)"><g id="consHeatAni" class="stream" style="--dx:111.000px;--dy:0.000px"><circle cx="659.0" cy="380.0"/><circle cx="770.0" cy="380.0"/><circle cx="881.0" cy="380.0"/><circle cx="992.0" cy="380.0"/><circle cx="1103.0" cy="380.0"/><circle cx="1214.0" cy="380.0"/></g></g>
|
||||||
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
|
||||||
|
|
||||||
<line x1="920" y1="670" x2="1220" y2="670" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
<line x1="920" y1="670" x2="1220" y2="670" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
<line id="consEVani" class="stream" x1="920" y1="670" x2="1220" y2="670" stroke-linecap="round"
|
<g clip-path="url(#clip_consEVani)"><g id="consEVani" class="stream" style="--dx:111.000px;--dy:0.000px"><circle cx="809.0" cy="670.0"/><circle cx="920.0" cy="670.0"/><circle cx="1031.0" cy="670.0"/><circle cx="1142.0" cy="670.0"/><circle cx="1253.0" cy="670.0"/></g></g>
|
||||||
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
|
||||||
|
|
||||||
<line x1="920" y1="70" x2="1220" y2="70" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
<line x1="920" y1="70" x2="1220" y2="70" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
<line id="consEVOGani" class="stream" x1="920" y1="70" x2="1220" y2="70" stroke-linecap="round"
|
<g clip-path="url(#clip_consEVOGani)"><g id="consEVOGani" class="stream" style="--dx:111.000px;--dy:0.000px"><circle cx="809.0" cy="70.0"/><circle cx="920.0" cy="70.0"/><circle cx="1031.0" cy="70.0"/><circle cx="1142.0" cy="70.0"/><circle cx="1253.0" cy="70.0"/></g></g>
|
||||||
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
|
||||||
|
|
||||||
<line x1="100" y1="380" x2="430" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
<line x1="100" y1="380" x2="430" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
<line id="consGridani" class="stream" x1="100" y1="380" x2="430" y2="380" stroke-linecap="round"
|
<g clip-path="url(#clip_consGridani)"><g id="consGridani" class="stream" style="--dx:111.000px;--dy:0.000px"><circle cx="-11.0" cy="380.0"/><circle cx="100.0" cy="380.0"/><circle cx="211.0" cy="380.0"/><circle cx="322.0" cy="380.0"/><circle cx="433.0" cy="380.0"/></g></g>
|
||||||
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
|
||||||
|
|
||||||
<line x1="180" y1="130" x2="430" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
<line x1="180" y1="130" x2="430" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
<line id="pvani" class="stream" x1="180" y1="130" x2="430" y2="380" stroke-linecap="round"
|
<g clip-path="url(#clip_pvani)"><g id="pvani" class="stream" style="--dx:78.489px;--dy:78.489px"><circle cx="101.5" cy="51.5"/><circle cx="180.0" cy="130.0"/><circle cx="258.5" cy="208.5"/><circle cx="337.0" cy="287.0"/><circle cx="415.5" cy="365.5"/><circle cx="494.0" cy="444.0"/></g></g>
|
||||||
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
|
||||||
|
|
||||||
<line x1="180" y1="630" x2="430" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
<line x1="180" y1="630" x2="430" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
<line id="battani" class="stream" x1="180" y1="630" x2="430" y2="380" stroke-linecap="round"
|
<g clip-path="url(#clip_battani)"><g id="battani" class="stream" style="--dx:78.489px;--dy:-78.489px"><circle cx="101.5" cy="708.5"/><circle cx="180.0" cy="630.0"/><circle cx="258.5" cy="551.5"/><circle cx="337.0" cy="473.0"/><circle cx="415.5" cy="394.5"/><circle cx="494.0" cy="316.0"/></g></g>
|
||||||
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
|
||||||
|
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -127,21 +136,18 @@
|
|||||||
style="position:absolute;top:0;"
|
style="position:absolute;top:0;"
|
||||||
viewBox="-100 -100 1600 950" width="100%" height="100%" id="realtimeSvg">
|
viewBox="-100 -100 1600 950" width="100%" height="100%" id="realtimeSvg">
|
||||||
<defs>
|
<defs>
|
||||||
<filter id="shadow" x="-0.5" y="-0.5" width="200%" height="200%">
|
<filter id="shadow" x="-0.3" y="-0.3" width="160%" height="160%">
|
||||||
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
|
<feMorphology in="SourceAlpha" result="offOut" operator="dilate" radius="0.7" />
|
||||||
<feMorphology in="offOut" result="offOut" operator="dilate" radius="0.7" />
|
|
||||||
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="0.5" />
|
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="0.5" />
|
||||||
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
|
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
|
||||||
</filter>
|
</filter>
|
||||||
<filter id="shadowMiddle" x="-1.0" y="-1.0" width="300%" height="300%">
|
<filter id="shadowMiddle" x="-0.4" y="-0.4" width="180%" height="180%">
|
||||||
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
|
<feMorphology in="SourceAlpha" result="offOut" operator="dilate" radius="3" />
|
||||||
<feMorphology in="offOut" result="offOut" operator="dilate" radius="3" />
|
|
||||||
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="1" />
|
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="1" />
|
||||||
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
|
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
|
||||||
</filter>
|
</filter>
|
||||||
<filter id="shadowBig" x="-1" y="-1" width="300%" height="300%">
|
<filter id="shadowBig" x="-0.45" y="-0.45" width="190%" height="190%">
|
||||||
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
|
<feMorphology in="SourceAlpha" result="offOut" operator="dilate" radius="3" />
|
||||||
<feMorphology in="offOut" result="offOut" operator="dilate" radius="3" />
|
|
||||||
<feGaussianBlur result="offOut" in="offOut" stdDeviation="2" />
|
<feGaussianBlur result="offOut" in="offOut" stdDeviation="2" />
|
||||||
<feBlend in="SourceGraphic" in2="offOut" mode="normal" />
|
<feBlend in="SourceGraphic" in2="offOut" mode="normal" />
|
||||||
</filter>
|
</filter>
|
||||||
@@ -581,7 +587,7 @@
|
|||||||
style='display:none;mix-blend-mode: difference;fill:#70CCBB;' href="#heater" />
|
style='display:none;mix-blend-mode: difference;fill:#70CCBB;' href="#heater" />
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<g transform="translate(330,280), scale(0.70,0.70)" id="waterInfo" class="clickable" onclick="openModal('watering')">
|
<g transform="translate(330,280), scale(0.90,0.90)" id="waterInfo" class="clickable" onclick="openModal('watering')">
|
||||||
<animateMotion begin="0.5s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
<animateMotion begin="0.5s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
keySplines=".1,0,.27,1" path="M0 0 L340 0" fill="freeze" />
|
keySplines=".1,0,.27,1" path="M0 0 L340 0" fill="freeze" />
|
||||||
<animateMotion begin="1.2s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
<animateMotion begin="1.2s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
@@ -591,7 +597,7 @@
|
|||||||
d="M 99.863863 22.00012 A 78 78 0 1 0 100 22" />
|
d="M 99.863863 22.00012 A 78 78 0 1 0 100 22" />
|
||||||
<use href="#water" transform="translate(60,55), scale(0.20,0.20)" fill="#3A6292" />
|
<use href="#water" transform="translate(60,55), scale(0.20,0.20)" fill="#3A6292" />
|
||||||
<!-- Wasserstand und Temperatur werden von der Bewässerungssteuerung nicht unterstützt.
|
<!-- Wasserstand und Temperatur werden von der Bewässerungssteuerung nicht unterstützt.
|
||||||
<text id="waterText" filter="url(#shadowMiddle)" class="powerTextClass" text-anchor="middle" x="100" y="55">--.- cm</text>
|
<text id="waterText" filter="url(#shadowMiddle)" class="powerTextClass" text-anchor="middle" x="100" y="55">-.- cm</text>
|
||||||
<text id="waterTemp" filter="url(#shadowMiddle)" class="powerTextClass" text-anchor="middle" x="100" y="88">-.- °C</text>
|
<text id="waterTemp" filter="url(#shadowMiddle)" class="powerTextClass" text-anchor="middle" x="100" y="88">-.- °C</text>
|
||||||
-->
|
-->
|
||||||
<use id="wateringFrontIcon" href="#gardenPlantIcon" transform="translate(152,162),rotate(310),scale(1.3)" fill="#6c757d" color="#6c757d">
|
<use id="wateringFrontIcon" href="#gardenPlantIcon" transform="translate(152,162),rotate(310),scale(1.3)" fill="#6c757d" color="#6c757d">
|
||||||
|
|||||||
@@ -1,638 +0,0 @@
|
|||||||
@keyframes opaque {
|
|
||||||
0% {
|
|
||||||
opacity: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes resizeanim {
|
|
||||||
0%,to {
|
|
||||||
opacity: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-canvas {
|
|
||||||
position: relative;
|
|
||||||
user-select: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-canvas ::-webkit-scrollbar {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
width: 6px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-canvas ::-webkit-scrollbar-thumb {
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: rgba(0,0,0,.5);
|
|
||||||
box-shadow: 0 0 1px rgba(255,255,255,.5);
|
|
||||||
-webkit-box-shadow: 0 0 1px rgba(255,255,255,.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-inner {
|
|
||||||
position: relative
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-text tspan {
|
|
||||||
font-family: inherit
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-mouseover-inactive {
|
|
||||||
transition: .15s ease all;
|
|
||||||
opacity: .2
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-legend-text {
|
|
||||||
padding-left: 15px;
|
|
||||||
margin-left: -15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-series-collapsed {
|
|
||||||
opacity: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip {
|
|
||||||
border-radius: 5px;
|
|
||||||
box-shadow: 2px 2px 6px -4px #999;
|
|
||||||
cursor: default;
|
|
||||||
font-size: 14px;
|
|
||||||
left: 62px;
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
z-index: 12;
|
|
||||||
transition: .15s ease all
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip.apexcharts-active {
|
|
||||||
opacity: 1;
|
|
||||||
transition: .15s ease all
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip.apexcharts-theme-light {
|
|
||||||
border: 1px solid #e3e3e3;
|
|
||||||
background: rgba(255,255,255,.96)
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip.apexcharts-theme-dark {
|
|
||||||
color: #fff;
|
|
||||||
background: rgba(30,30,30,.8)
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip * {
|
|
||||||
font-family: inherit
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-title {
|
|
||||||
padding: 6px;
|
|
||||||
font-size: 15px;
|
|
||||||
margin-bottom: 4px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip.apexcharts-theme-light .apexcharts-tooltip-title {
|
|
||||||
background: #eceff1;
|
|
||||||
border-bottom: 1px solid #ddd
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip.apexcharts-theme-dark .apexcharts-tooltip-title {
|
|
||||||
background: rgba(0,0,0,.7);
|
|
||||||
border-bottom: 1px solid #333
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-text-goals-value,.apexcharts-tooltip-text-y-value,.apexcharts-tooltip-text-z-value {
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: 5px;
|
|
||||||
font-weight: 600
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-text-goals-label:empty,.apexcharts-tooltip-text-goals-value:empty,.apexcharts-tooltip-text-y-label:empty,.apexcharts-tooltip-text-y-value:empty,.apexcharts-tooltip-text-z-value:empty,.apexcharts-tooltip-title:empty {
|
|
||||||
display: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-text-goals-label,.apexcharts-tooltip-text-goals-value {
|
|
||||||
padding: 6px 0 5px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-goals-group,.apexcharts-tooltip-text-goals-label,.apexcharts-tooltip-text-goals-value {
|
|
||||||
display: flex
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-text-goals-label:not(:empty),.apexcharts-tooltip-text-goals-value:not(:empty) {
|
|
||||||
margin-top: -6px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-marker {
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
position: relative;
|
|
||||||
top: 0;
|
|
||||||
margin-right: 10px;
|
|
||||||
border-radius: 50%
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-series-group {
|
|
||||||
padding: 0 10px;
|
|
||||||
display: none;
|
|
||||||
text-align: left;
|
|
||||||
justify-content: left;
|
|
||||||
align-items: center
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-series-group.apexcharts-active .apexcharts-tooltip-marker {
|
|
||||||
opacity: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-series-group.apexcharts-active,.apexcharts-tooltip-series-group:last-child {
|
|
||||||
padding-bottom: 4px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-series-group-hidden {
|
|
||||||
opacity: 0;
|
|
||||||
height: 0;
|
|
||||||
line-height: 0;
|
|
||||||
padding: 0!important
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-y-group {
|
|
||||||
padding: 6px 0 5px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-custom-tooltip,.apexcharts-tooltip-box {
|
|
||||||
padding: 4px 8px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-boxPlot {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column-reverse
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-box>div {
|
|
||||||
margin: 4px 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-box span.value {
|
|
||||||
font-weight: 700
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-rangebar {
|
|
||||||
padding: 5px 8px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-rangebar .category {
|
|
||||||
font-weight: 600;
|
|
||||||
color: #777
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-tooltip-rangebar .series-name {
|
|
||||||
font-weight: 700;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 5px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip,.apexcharts-yaxistooltip {
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
color: #373d3f;
|
|
||||||
font-size: 13px;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 2px;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 10;
|
|
||||||
background: #eceff1;
|
|
||||||
border: 1px solid #90a4ae
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip {
|
|
||||||
padding: 9px 10px;
|
|
||||||
transition: .15s ease all
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip.apexcharts-theme-dark {
|
|
||||||
background: rgba(0,0,0,.7);
|
|
||||||
border: 1px solid rgba(0,0,0,.5);
|
|
||||||
color: #fff
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip:after,.apexcharts-xaxistooltip:before {
|
|
||||||
left: 50%;
|
|
||||||
border: solid transparent;
|
|
||||||
content: " ";
|
|
||||||
height: 0;
|
|
||||||
width: 0;
|
|
||||||
position: absolute;
|
|
||||||
pointer-events: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip:after {
|
|
||||||
border-color: transparent;
|
|
||||||
border-width: 6px;
|
|
||||||
margin-left: -6px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip:before {
|
|
||||||
border-color: transparent;
|
|
||||||
border-width: 7px;
|
|
||||||
margin-left: -7px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip-bottom:after,.apexcharts-xaxistooltip-bottom:before {
|
|
||||||
bottom: 100%
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip-top:after,.apexcharts-xaxistooltip-top:before {
|
|
||||||
top: 100%
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip-bottom:after {
|
|
||||||
border-bottom-color: #eceff1
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip-bottom:before {
|
|
||||||
border-bottom-color: #90a4ae
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:after,.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:before {
|
|
||||||
border-bottom-color: rgba(0,0,0,.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip-top:after {
|
|
||||||
border-top-color: #eceff1
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip-top:before {
|
|
||||||
border-top-color: #90a4ae
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip-top.apexcharts-theme-dark:after,.apexcharts-xaxistooltip-top.apexcharts-theme-dark:before {
|
|
||||||
border-top-color: rgba(0,0,0,.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xaxistooltip.apexcharts-active {
|
|
||||||
opacity: 1;
|
|
||||||
transition: .15s ease all
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip {
|
|
||||||
padding: 4px 10px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip.apexcharts-theme-dark {
|
|
||||||
background: rgba(0,0,0,.7);
|
|
||||||
border: 1px solid rgba(0,0,0,.5);
|
|
||||||
color: #fff
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip:after,.apexcharts-yaxistooltip:before {
|
|
||||||
top: 50%;
|
|
||||||
border: solid transparent;
|
|
||||||
content: " ";
|
|
||||||
height: 0;
|
|
||||||
width: 0;
|
|
||||||
position: absolute;
|
|
||||||
pointer-events: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip:after {
|
|
||||||
border-color: transparent;
|
|
||||||
border-width: 6px;
|
|
||||||
margin-top: -6px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip:before {
|
|
||||||
border-color: transparent;
|
|
||||||
border-width: 7px;
|
|
||||||
margin-top: -7px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip-left:after,.apexcharts-yaxistooltip-left:before {
|
|
||||||
left: 100%
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip-right:after,.apexcharts-yaxistooltip-right:before {
|
|
||||||
right: 100%
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip-left:after {
|
|
||||||
border-left-color: #eceff1
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip-left:before {
|
|
||||||
border-left-color: #90a4ae
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip-left.apexcharts-theme-dark:after,.apexcharts-yaxistooltip-left.apexcharts-theme-dark:before {
|
|
||||||
border-left-color: rgba(0,0,0,.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip-right:after {
|
|
||||||
border-right-color: #eceff1
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip-right:before {
|
|
||||||
border-right-color: #90a4ae
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip-right.apexcharts-theme-dark:after,.apexcharts-yaxistooltip-right.apexcharts-theme-dark:before {
|
|
||||||
border-right-color: rgba(0,0,0,.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip.apexcharts-active {
|
|
||||||
opacity: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-yaxistooltip-hidden {
|
|
||||||
display: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xcrosshairs,.apexcharts-ycrosshairs {
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0;
|
|
||||||
transition: .15s ease all
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-xcrosshairs.apexcharts-active,.apexcharts-ycrosshairs.apexcharts-active {
|
|
||||||
opacity: 1;
|
|
||||||
transition: .15s ease all
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-ycrosshairs-hidden {
|
|
||||||
opacity: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-selection-rect {
|
|
||||||
cursor: move
|
|
||||||
}
|
|
||||||
|
|
||||||
.svg_select_boundingRect,.svg_select_points_rot {
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-selection-rect+g .svg_select_boundingRect,.apexcharts-selection-rect+g .svg_select_points_rot {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-selection-rect+g .svg_select_points_l,.apexcharts-selection-rect+g .svg_select_points_r {
|
|
||||||
cursor: ew-resize;
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible
|
|
||||||
}
|
|
||||||
|
|
||||||
.svg_select_points {
|
|
||||||
fill: #efefef;
|
|
||||||
stroke: #333;
|
|
||||||
rx: 2
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-svg.apexcharts-zoomable.hovering-zoom {
|
|
||||||
cursor: crosshair
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-svg.apexcharts-zoomable.hovering-pan {
|
|
||||||
cursor: move
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-menu-icon,.apexcharts-pan-icon,.apexcharts-reset-icon,.apexcharts-selection-icon,.apexcharts-toolbar-custom-icon,.apexcharts-zoom-icon,.apexcharts-zoomin-icon,.apexcharts-zoomout-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
line-height: 24px;
|
|
||||||
color: #6e8192;
|
|
||||||
text-align: center
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-menu-icon svg,.apexcharts-reset-icon svg,.apexcharts-zoom-icon svg,.apexcharts-zoomin-icon svg,.apexcharts-zoomout-icon svg {
|
|
||||||
fill: #6e8192
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-selection-icon svg {
|
|
||||||
fill: #444;
|
|
||||||
transform: scale(.76)
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-theme-dark .apexcharts-menu-icon svg,.apexcharts-theme-dark .apexcharts-pan-icon svg,.apexcharts-theme-dark .apexcharts-reset-icon svg,.apexcharts-theme-dark .apexcharts-selection-icon svg,.apexcharts-theme-dark .apexcharts-toolbar-custom-icon svg,.apexcharts-theme-dark .apexcharts-zoom-icon svg,.apexcharts-theme-dark .apexcharts-zoomin-icon svg,.apexcharts-theme-dark .apexcharts-zoomout-icon svg {
|
|
||||||
fill: #f3f4f5
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-canvas .apexcharts-reset-zoom-icon.apexcharts-selected svg,.apexcharts-canvas .apexcharts-selection-icon.apexcharts-selected svg,.apexcharts-canvas .apexcharts-zoom-icon.apexcharts-selected svg {
|
|
||||||
fill: #008ffb
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-theme-light .apexcharts-menu-icon:hover svg,.apexcharts-theme-light .apexcharts-reset-icon:hover svg,.apexcharts-theme-light .apexcharts-selection-icon:not(.apexcharts-selected):hover svg,.apexcharts-theme-light .apexcharts-zoom-icon:not(.apexcharts-selected):hover svg,.apexcharts-theme-light .apexcharts-zoomin-icon:hover svg,.apexcharts-theme-light .apexcharts-zoomout-icon:hover svg {
|
|
||||||
fill: #333
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-menu-icon,.apexcharts-selection-icon {
|
|
||||||
position: relative
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-reset-icon {
|
|
||||||
margin-left: 5px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-menu-icon,.apexcharts-reset-icon,.apexcharts-zoom-icon {
|
|
||||||
transform: scale(.85)
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-zoomin-icon,.apexcharts-zoomout-icon {
|
|
||||||
transform: scale(.7)
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-zoomout-icon {
|
|
||||||
margin-right: 3px
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-pan-icon {
|
|
||||||
transform: scale(.62);
|
|
||||||
position: relative;
|
|
||||||
left: 1px;
|
|
||||||
top: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-pan-icon svg {
|
|
||||||
fill: #fff;
|
|
||||||
stroke: #6e8192;
|
|
||||||
stroke-width: 2
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-pan-icon.apexcharts-selected svg {
|
|
||||||
stroke: #008ffb
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-pan-icon:not(.apexcharts-selected):hover svg {
|
|
||||||
stroke: #333
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-toolbar {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 11;
|
|
||||||
max-width: 176px;
|
|
||||||
text-align: right;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 0 6px 2px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-menu {
|
|
||||||
background: #fff;
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 3px;
|
|
||||||
right: 10px;
|
|
||||||
opacity: 0;
|
|
||||||
min-width: 110px;
|
|
||||||
transition: .15s ease all;
|
|
||||||
pointer-events: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-menu.apexcharts-menu-open {
|
|
||||||
opacity: 1;
|
|
||||||
pointer-events: all;
|
|
||||||
transition: .15s ease all
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-menu-item {
|
|
||||||
padding: 6px 7px;
|
|
||||||
font-size: 12px;
|
|
||||||
cursor: pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-theme-light .apexcharts-menu-item:hover {
|
|
||||||
background: #eee
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-theme-dark .apexcharts-menu {
|
|
||||||
background: rgba(0,0,0,.7);
|
|
||||||
color: #fff
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width:768px) {
|
|
||||||
.apexcharts-canvas:hover .apexcharts-toolbar {
|
|
||||||
opacity: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-canvas .apexcharts-element-hidden,.apexcharts-datalabel.apexcharts-element-hidden,.apexcharts-hide .apexcharts-series-points {
|
|
||||||
opacity: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-datalabel,.apexcharts-datalabel-label,.apexcharts-datalabel-value,.apexcharts-datalabels,.apexcharts-pie-label {
|
|
||||||
cursor: default;
|
|
||||||
pointer-events: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-pie-label-delay {
|
|
||||||
opacity: 0;
|
|
||||||
animation-name: opaque;
|
|
||||||
animation-duration: .3s;
|
|
||||||
animation-fill-mode: forwards;
|
|
||||||
animation-timing-function: ease
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-legend {
|
|
||||||
display: flex;
|
|
||||||
overflow: auto;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
.apexcharts-legend.apx-legend-position-bottom, .apexcharts-legend.apx-legend-position-top {
|
|
||||||
flex-wrap: wrap
|
|
||||||
}
|
|
||||||
.apexcharts-legend.apx-legend-position-right, .apexcharts-legend.apx-legend-position-left {
|
|
||||||
flex-direction: column;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
.apexcharts-legend.apx-legend-position-bottom.apexcharts-align-left, .apexcharts-legend.apx-legend-position-top.apexcharts-align-left, .apexcharts-legend.apx-legend-position-right, .apexcharts-legend.apx-legend-position-left {
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
.apexcharts-legend.apx-legend-position-bottom.apexcharts-align-center, .apexcharts-legend.apx-legend-position-top.apexcharts-align-center {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.apexcharts-legend.apx-legend-position-bottom.apexcharts-align-right, .apexcharts-legend.apx-legend-position-top.apexcharts-align-right {
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
.apexcharts-legend-series {
|
|
||||||
cursor: pointer;
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
.apexcharts-legend.apx-legend-position-bottom .apexcharts-legend-series, .apexcharts-legend.apx-legend-position-top .apexcharts-legend-series{
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.apexcharts-legend-text {
|
|
||||||
position: relative;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.apexcharts-legend-text *, .apexcharts-legend-marker * {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.apexcharts-legend-marker {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-right: 3px;
|
|
||||||
border-style: solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-legend.apexcharts-align-right .apexcharts-legend-series, .apexcharts-legend.apexcharts-align-left .apexcharts-legend-series{
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.apexcharts-legend-series.apexcharts-no-click {
|
|
||||||
cursor: auto;
|
|
||||||
}
|
|
||||||
.apexcharts-legend .apexcharts-hidden-zero-series, .apexcharts-legend .apexcharts-hidden-null-series {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
.apexcharts-inactive-legend {
|
|
||||||
opacity: 0.45;
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-annotation-rect,.apexcharts-area-series .apexcharts-area,.apexcharts-area-series .apexcharts-series-markers .apexcharts-marker.no-pointer-events,.apexcharts-gridline,.apexcharts-line,.apexcharts-line-series .apexcharts-series-markers .apexcharts-marker.no-pointer-events,.apexcharts-point-annotation-label,.apexcharts-radar-series path,.apexcharts-radar-series polygon,.apexcharts-toolbar svg,.apexcharts-tooltip .apexcharts-marker,.apexcharts-xaxis-annotation-label,.apexcharts-yaxis-annotation-label,.apexcharts-zoom-rect {
|
|
||||||
pointer-events: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.apexcharts-marker {
|
|
||||||
transition: .15s ease all
|
|
||||||
}
|
|
||||||
|
|
||||||
.resize-triggers {
|
|
||||||
animation: 1ms resizeanim;
|
|
||||||
visibility: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden
|
|
||||||
}
|
|
||||||
|
|
||||||
.contract-trigger:before,.resize-triggers,.resize-triggers>div {
|
|
||||||
content: " ";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.resize-triggers>div {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
background: #eee;
|
|
||||||
overflow: auto
|
|
||||||
}
|
|
||||||
|
|
||||||
.contract-trigger:before {
|
|
||||||
overflow: hidden;
|
|
||||||
width: 200%;
|
|
||||||
height: 200%
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
svg{-ms-touch-action:none;touch-action:none}image,text,.jvm-zoomin,.jvm-zoomout{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.jvm-container{-ms-touch-action:none;touch-action:none;position:relative;overflow:hidden;height:100%;width:100%}.jvm-tooltip{border-radius:3px;background-color:#5c5cff;font-family:sans-serif,Verdana;font-size:smaller;box-shadow:1px 2px 12px rgba(0,0,0,0.2);padding:3px 5px;white-space:nowrap;position:absolute;display:none;color:#FFF}.jvm-tooltip.active{display:block}.jvm-zoom-btn{border-radius:3px;background-color:#292929;padding:3px;box-sizing:border-box;position:absolute;line-height:10px;cursor:pointer;color:#FFF;height:15px;width:15px;left:10px}.jvm-zoom-btn.jvm-zoomout{top:30px}.jvm-zoom-btn.jvm-zoomin{top:10px}.jvm-series-container{right:15px;position:absolute}.jvm-series-container.jvm-series-h{bottom:15px}.jvm-series-container.jvm-series-v{top:15px}.jvm-series-container .jvm-legend{background-color:#fff;border:1px solid #e5e7eb;margin-left:.75rem;border-radius:.25rem;border-color:#e5e7eb;padding:.6rem;box-shadow:0 1px 2px 0 rgba(0,0,0,0.05);float:left}.jvm-series-container .jvm-legend .jvm-legend-title{line-height:1;border-bottom:1px solid #e5e7eb;padding-bottom:.5rem;margin-bottom:.575rem;text-align:left}.jvm-series-container .jvm-legend .jvm-legend-inner{overflow:hidden}.jvm-series-container .jvm-legend .jvm-legend-inner .jvm-legend-tick{overflow:hidden;min-width:40px}.jvm-series-container .jvm-legend .jvm-legend-inner .jvm-legend-tick:not(:first-child){margin-top:.575rem}.jvm-series-container .jvm-legend .jvm-legend-inner .jvm-legend-tick .jvm-legend-tick-sample{border-radius:4px;margin-right:.65rem;height:16px;width:16px;float:left}.jvm-series-container .jvm-legend .jvm-legend-inner .jvm-legend-tick .jvm-legend-tick-text{font-size:12px;text-align:center;float:left}.jvm-line[animation="true"]{-webkit-animation:jvm-line-animation 10s linear forwards infinite;animation:jvm-line-animation 10s linear forwards infinite}@-webkit-keyframes jvm-line-animation{from{stroke-dashoffset:250}}@keyframes jvm-line-animation{from{stroke-dashoffset:250}}
|
|
||||||
@@ -10,4 +10,12 @@
|
|||||||
background-position: center;
|
background-position: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Schieberegler in den Modals (Autoladung, Heizstab, Thermostat).
|
||||||
|
Der gefuellte Anteil kommt aus --background-size, gesetzt von
|
||||||
|
bindModalSlider() in js/solar/common.js. */
|
||||||
|
input[type='range']::-webkit-slider-runnable-track {
|
||||||
|
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
|
||||||
|
background-size: var(--background-size, 0%) 100%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,21 @@ function isLocal(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kleine HTTP-GET-Anfrage im Heimnetz, Antwort als JSON-Array.
|
||||||
|
* Ersetzt die frueher in carOG.php, heater.php und AutoAction.php je einzeln
|
||||||
|
* definierte Funktion getSSLPage().
|
||||||
|
*/
|
||||||
|
function httpGetJson($url){
|
||||||
|
$curlSession = curl_init();
|
||||||
|
curl_setopt($curlSession, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($curlSession, CURLOPT_TIMEOUT, 5);
|
||||||
|
$response = curl_exec($curlSession);
|
||||||
|
curl_close($curlSession);
|
||||||
|
return json_decode($response, true);
|
||||||
|
}
|
||||||
|
|
||||||
function checkLogin(){
|
function checkLogin(){
|
||||||
$mysql = new mysqli($GLOBALS["mysql_server"],$GLOBALS["mysql_user"],$GLOBALS["mysql_pass"],$GLOBALS["mysql_db"]);
|
$mysql = new mysqli($GLOBALS["mysql_server"],$GLOBALS["mysql_user"],$GLOBALS["mysql_pass"],$GLOBALS["mysql_db"]);
|
||||||
if(isLocal()){
|
if(isLocal()){
|
||||||
|
|||||||
@@ -22,16 +22,12 @@ if (isset($_GET["addUser"])) {
|
|||||||
<link rel="stylesheet" href="assets/fonts/font_poppins.css" media="print" onload="this.media='all'" />
|
<link rel="stylesheet" href="assets/fonts/font_poppins.css" media="print" onload="this.media='all'" />
|
||||||
<!--end::Fonts-->
|
<!--end::Fonts-->
|
||||||
|
|
||||||
<!--begin::Third Party Plugin(OverlayScrollbars)
|
|
||||||
<link rel="stylesheet" href="css/overlayscrollbars.min.css" />-->
|
|
||||||
<!--end::Third Party Plugin(OverlayScrollbars)-->
|
|
||||||
|
|
||||||
<!--begin::Third Party Plugin(Bootstrap Icons)-->
|
<!--begin::Third Party Plugin(Bootstrap Icons)-->
|
||||||
<link rel="stylesheet" href="css/bootstrap-icons.min.css" />
|
<link rel="stylesheet" href="css/bootstrap-icons.min.css" />
|
||||||
<!--end::Third Party Plugin(Bootstrap Icons)-->
|
<!--end::Third Party Plugin(Bootstrap Icons)-->
|
||||||
|
|
||||||
<!--begin::Required Plugin(AdminLTE)-->
|
<!--begin::Required Plugin(AdminLTE)-->
|
||||||
<link rel="stylesheet" href="./css/adminlte.css?v=2" />
|
<link rel="stylesheet" href="./css/adminlte.min.css?v=2" />
|
||||||
<!--end::Required Plugin(AdminLTE)-->
|
<!--end::Required Plugin(AdminLTE)-->
|
||||||
|
|
||||||
|
|
||||||
@@ -97,40 +93,33 @@ if (isset($_GET["addUser"])) {
|
|||||||
ENDE;
|
ENDE;
|
||||||
}
|
}
|
||||||
} else if (checkLogin()) {
|
} else if (checkLogin()) {
|
||||||
|
/*
|
||||||
include "restricted/header.php";
|
* Seitentabelle: Vorlage, Seitenskripte und welche Bibliotheken die Seite
|
||||||
|
* ueberhaupt braucht. Frueher wurden Chart.js, MQTT & Co. auf jeder Seite
|
||||||
|
* geladen - die Home-Seite etwa zeichnet gar keine Diagramme.
|
||||||
|
*/
|
||||||
|
$pages = [
|
||||||
|
"solar" => ["template" => "solar.php", "mqtt" => true, "charts" => true, "meteogram" => true,
|
||||||
|
"scripts" => ["js/solar/solarMQTT.js"]],
|
||||||
|
"home" => ["template" => "home.php", "mqtt" => true, "charts" => false, "meteogram" => false,
|
||||||
|
"scripts" => ["js/solar/autoActionFuncs.js", "js/solar/homeMQTT.js"]],
|
||||||
|
"heat" => ["template" => "heat.php", "mqtt" => true, "charts" => true, "meteogram" => false,
|
||||||
|
"scripts" => ["js/solar/heatMQTT.js"]],
|
||||||
|
"history" => ["template" => "history.php", "mqtt" => false, "charts" => true, "meteogram" => false,
|
||||||
|
"scripts" => ["js/solar/historyMQTT.js"]],
|
||||||
|
"weather" => ["template" => "weather.php", "mqtt" => true, "charts" => false, "meteogram" => true,
|
||||||
|
"scripts" => ["js/solar/weatherMQTT.js"]],
|
||||||
|
];
|
||||||
|
|
||||||
if(!isset($_GET["action"])){
|
// Unbekannte oder fehlende Aktion faellt auf die Solar-Seite zurueck.
|
||||||
|
if (!isset($_GET["action"]) || !isset($pages[$_GET["action"]])) {
|
||||||
$_GET["action"] = "solar";
|
$_GET["action"] = "solar";
|
||||||
}
|
}
|
||||||
$resource_content = "";
|
$page = $pages[$_GET["action"]];
|
||||||
switch($_GET["action"]){
|
|
||||||
case "solar":
|
|
||||||
$resource_content .= str_replace("%%INSERTSVG%%", file_get_contents('assets/img/realtime.svg'), file_get_contents('restricted/solar.html'));
|
|
||||||
$resource_content .= file_get_contents('restricted/footer.html');
|
|
||||||
$resource_content .= "<script src='js/solar/solarMQTT.js?v=" . filemtime('js/solar/solarMQTT.js') . "'></script>";
|
|
||||||
break;
|
|
||||||
case "home":
|
|
||||||
include "restricted/home.php";
|
|
||||||
$resource_content .= file_get_contents('restricted/footer.html');
|
|
||||||
$resource_content .= "<script src='js/solar/autoActionFuncs.js'></script>";
|
|
||||||
$resource_content .= "<script src='js/solar/homeMQTT.js'></script>";
|
|
||||||
break;
|
|
||||||
case "heat":
|
|
||||||
$resource_content .= file_get_contents('restricted/heat.html');
|
|
||||||
$resource_content .= file_get_contents('restricted/footer.html');
|
|
||||||
$resource_content .= "<script src='js/solar/heatMQTT.js'></script>";
|
|
||||||
break;
|
|
||||||
case "history":
|
|
||||||
$resource_content .= file_get_contents('restricted/history.html');
|
|
||||||
$resource_content .= file_get_contents('restricted/footer.html');
|
|
||||||
$resource_content .= "<script src='js/solar/historyMQTT.js'></script>";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
echo $resource_content;
|
include "restricted/header.php";
|
||||||
|
include "restricted/" . $page["template"];
|
||||||
|
include "restricted/footer.php";
|
||||||
} else {
|
} else {
|
||||||
echo <<<ENDE
|
echo <<<ENDE
|
||||||
<html>
|
<html>
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
/*!
|
|
||||||
* chartjs-adapter-luxon v1.3.1
|
|
||||||
* https://www.chartjs.org
|
|
||||||
* (c) 2023 chartjs-adapter-luxon Contributors
|
|
||||||
* Released under the MIT license
|
|
||||||
*/
|
|
||||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("chart.js"),require("luxon")):"function"==typeof define&&define.amd?define(["chart.js","luxon"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Chart,e.luxon)}(this,(function(e,t){"use strict";const n={datetime:t.DateTime.DATETIME_MED_WITH_SECONDS,millisecond:"h:mm:ss.SSS a",second:t.DateTime.TIME_WITH_SECONDS,minute:t.DateTime.TIME_SIMPLE,hour:{hour:"numeric"},day:{day:"numeric",month:"short"},week:"DD",month:{month:"short",year:"numeric"},quarter:"'Q'q - yyyy",year:{year:"numeric"}};e._adapters._date.override({_id:"luxon",_create:function(e){return t.DateTime.fromMillis(e,this.options)},init(e){this.options.locale||(this.options.locale=e.locale)},formats:function(){return n},parse:function(e,n){const i=this.options,r=typeof e;return null===e||"undefined"===r?null:("number"===r?e=this._create(e):"string"===r?e="string"==typeof n?t.DateTime.fromFormat(e,n,i):t.DateTime.fromISO(e,i):e instanceof Date?e=t.DateTime.fromJSDate(e,i):"object"!==r||e instanceof t.DateTime||(e=t.DateTime.fromObject(e,i)),e.isValid?e.valueOf():null)},format:function(e,t){const n=this._create(e);return"string"==typeof t?n.toFormat(t):n.toLocaleString(t)},add:function(e,t,n){const i={};return i[n]=t,this._create(e).plus(i).valueOf()},diff:function(e,t,n){return this._create(e).diff(this._create(t)).as(n).valueOf()},startOf:function(e,t,n){if("isoWeek"===t){n=Math.trunc(Math.min(Math.max(0,n),6));const t=this._create(e);return t.minus({days:(t.weekday-n+7)%7}).startOf("day").valueOf()}return t?this._create(e).startOf(t).valueOf():e},endOf:function(e,t){return this._create(e).endOf(t).valueOf()}})}));
|
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Gemeinsame Bausteine der Dashboard-Seiten.
|
||||||
|
* Wird vor solarMQTT.js / homeMQTT.js / heatMQTT.js / historyMQTT.js geladen.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Sekunden als "HH:MM". */
|
||||||
|
String.prototype.toHHMM = function () {
|
||||||
|
var sec_num = parseInt(this, 10);
|
||||||
|
var hours = Math.floor(sec_num / 3600);
|
||||||
|
var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
|
||||||
|
if (hours < 10) { hours = "0" + hours; }
|
||||||
|
if (minutes < 10) { minutes = "0" + minutes; }
|
||||||
|
return hours + ':' + minutes;
|
||||||
|
};
|
||||||
|
|
||||||
|
function powerToString(power) {
|
||||||
|
if (Math.abs(power) > 999) {
|
||||||
|
power = power / 1000;
|
||||||
|
return power.toPrecision(3) + " kW";
|
||||||
|
} else {
|
||||||
|
return Math.round(power) + " W";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadingHTML(msg) {
|
||||||
|
return "<div class='m-4'><div class='spinner-border' role='status'><span class='visually-hidden'>Loading...</span></div> " + msg + "</div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Diagrammdaten holen und eintragen.
|
||||||
|
* params Funktion, die {FROM, TO} liefert (Zeitraum aendert sich zur Laufzeit)
|
||||||
|
* sunrise true -> Sonnenstands-Markierungen fuer denselben Zeitraum
|
||||||
|
* Objekt {FROM, TO} -> fester Zeitraum
|
||||||
|
* autoUpdate alle 5 Minuten neu laden
|
||||||
|
* updateMode an chart.update() durchgereicht ("none" = ohne Animation)
|
||||||
|
*/
|
||||||
|
async function getData(chart, url, options = {}) {
|
||||||
|
const {
|
||||||
|
params = null,
|
||||||
|
sunrise = false,
|
||||||
|
autoUpdate = true,
|
||||||
|
updateMode = undefined,
|
||||||
|
refreshMs = 5 * 60 * 1000
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const range = params ? params() : null;
|
||||||
|
const query = range ? "?FROM=" + range.FROM + "&TO=" + range.TO : "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
chart.options.events = []; // waehrend des Ladens keine Tooltips
|
||||||
|
const response = await fetch(url + query);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Response status: ${response.status}`);
|
||||||
|
}
|
||||||
|
chart.data = await response.json();
|
||||||
|
|
||||||
|
if (sunrise) {
|
||||||
|
const sunRange = sunrise === true ? range : sunrise;
|
||||||
|
const response2 = await fetch("ajax/getSunrise.php?FROM=" + sunRange.FROM + "&TO=" + sunRange.TO);
|
||||||
|
if (!response2.ok) {
|
||||||
|
throw new Error(`Response status: ${response2.status}`);
|
||||||
|
}
|
||||||
|
chart.options.plugins.annotation.annotations = await response2.json();
|
||||||
|
}
|
||||||
|
chart.options.events = ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'];
|
||||||
|
chart.update(updateMode);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("getData " + url + ": " + error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoUpdate) {
|
||||||
|
setTimeout(function () { getData(chart, url, options); }, refreshMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Vorgerendertes HTML-Schnipsel in ein Element laden. */
|
||||||
|
async function getStats(elem_id, url) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Response status: ${response.status}`);
|
||||||
|
}
|
||||||
|
document.getElementById(elem_id).innerHTML = await response.text();
|
||||||
|
} catch (error) {
|
||||||
|
console.log("getStats " + url + ": " + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formular des Modals per POST abschicken.
|
||||||
|
* Der Start/Stop-Knopf der Ladesteuerung schickt nur sich selbst.
|
||||||
|
*/
|
||||||
|
function submitFormAjax(event) {
|
||||||
|
let xmlhttp = new XMLHttpRequest();
|
||||||
|
|
||||||
|
xmlhttp.onreadystatechange = function () {
|
||||||
|
if (this.readyState === 4 && this.status === 200) {
|
||||||
|
setTimeout(function () { modalEV.hide(); }, 700);
|
||||||
|
if (xmlhttp.responseText) {
|
||||||
|
alert(xmlhttp.responseText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let post = "";
|
||||||
|
if (event.currentTarget.id == "evStart/Stop") {
|
||||||
|
post = "evStart/Stop=" + event.currentTarget.innerHTML;
|
||||||
|
} else {
|
||||||
|
const form = document.getElementById('modalEV').querySelector('form');
|
||||||
|
for (const element of Array.from(form.elements)) {
|
||||||
|
if (!element.name) continue;
|
||||||
|
if (element.type == "radio" || element.type == "checkbox") {
|
||||||
|
if (element.checked) {
|
||||||
|
post += element.name + "=" + encodeURIComponent(element.value) + "&";
|
||||||
|
}
|
||||||
|
} else if (element.type == "button") {
|
||||||
|
if (!element.classList.contains("accordion-button")) {
|
||||||
|
post += element.name + "=" + encodeURIComponent(element.innerHTML) + "&";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
post += element.name + "=" + encodeURIComponent(element.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schieberegler im Modal mit seiner Beschriftung verbinden.
|
||||||
|
* label(wert) liefert den anzuzeigenden Text.
|
||||||
|
*/
|
||||||
|
function bindModalSlider(slider, span, label) {
|
||||||
|
slider.oninput = function () {
|
||||||
|
const min = Number(slider.min);
|
||||||
|
const max = Number(slider.max);
|
||||||
|
const percent = (Number(slider.value) - min) * 100 / (max - min);
|
||||||
|
slider.style.setProperty("--background-size", `${percent}%`);
|
||||||
|
|
||||||
|
// Beschriftung mitlaufen lassen, an den Raendern etwas gebremst
|
||||||
|
let margin = percent;
|
||||||
|
if (margin < 10) {
|
||||||
|
margin = margin - 0.4 * margin;
|
||||||
|
} else if (margin < 85) {
|
||||||
|
margin = margin - 4;
|
||||||
|
} else {
|
||||||
|
margin = margin - 4 - 0.5 * (margin - 85);
|
||||||
|
}
|
||||||
|
span.setAttribute('style', 'margin-left:' + margin + '%;');
|
||||||
|
span.innerHTML = label(slider.value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Meteoblue-Meteogramm einhängen, sofern die Seite einen Platz dafür hat. */
|
||||||
|
function mountMeteogram() {
|
||||||
|
const target = document.getElementById("meteogram");
|
||||||
|
if (!target) return;
|
||||||
|
// loading="lazy": das Meteogramm ist ein vollstaendiges Fremd-Dokument und
|
||||||
|
// liegt unterhalb der Falz - es wird erst geladen, wenn man hinscrollt.
|
||||||
|
target.innerHTML = "<iframe loading='lazy' src='" + meteogramURL + "' frameborder='0' scrolling=NO' allowtransparency='true' sandbox='allow-same-origin allow-scripts allow-popups allow-popups-to-escape-sandbox' style='width: 100%;height: 500px;border: 0;overflow: hidden;'></iframe><!-- DO NOT REMOVE THIS LINK --><a href='https://www.meteoblue.com/de/wetter/woche/index' target='_blank' rel='noopener'></a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wetterkacheln aktualisieren (restricted/weather_cards.html).
|
||||||
|
* value(name) liefert den Wert zu weatherStation/<name> - die Seiten legen
|
||||||
|
* die MQTT-Werte unterschiedlich ab, deshalb der Zugriff über eine Funktion.
|
||||||
|
*/
|
||||||
|
function updateWeatherCards(value) {
|
||||||
|
const windDir = document.getElementById("windDir");
|
||||||
|
if (!windDir) return; // Seite ohne Wetterkacheln
|
||||||
|
windDir.style.transform = "rotate(" + (90 + Number(value("windDeg"))) + "deg)";
|
||||||
|
document.getElementById("windSpd").innerHTML = value("avgWindspeed");
|
||||||
|
document.getElementById("humidity").innerHTML = value("hum");
|
||||||
|
document.getElementById("temp").innerHTML = value("tempAmb");
|
||||||
|
document.getElementById("windDirGust").style.transform = "rotate(" + (90 + Number(value("gustDeg"))) + "deg)";
|
||||||
|
document.getElementById("windGust").innerHTML = value("maxgust");
|
||||||
|
document.getElementById("ambPress").innerHTML = Math.round(value("qff") * 10) / 10;
|
||||||
|
}
|
||||||
@@ -54,7 +54,9 @@ const solarMQTT = {
|
|||||||
function messageReceived(topic, message) {
|
function messageReceived(topic, message) {
|
||||||
setNestedProp(mqttData, topic, message);
|
setNestedProp(mqttData, topic, message);
|
||||||
if (topic == "solarManager/P_Load") {
|
if (topic == "solarManager/P_Load") {
|
||||||
setTimeout(function () { solarSVG.updateValuesMQTT(mqttData) }, 200); //give the object tree some time to build up and receive all values
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,52 +187,7 @@ var chartSettings = {
|
|||||||
document.addEventListener('readystatechange', function () {
|
document.addEventListener('readystatechange', function () {
|
||||||
if (event.target.readyState === "complete") {
|
if (event.target.readyState === "complete") {
|
||||||
solarMQTT.getMQTT();
|
solarMQTT.getMQTT();
|
||||||
getData(heatChart, 'ajax/getHeaterData.php');
|
getData(heatChart, 'ajax/getHeaterData.php', { sunrise: { FROM: -24, TO: 0 } });
|
||||||
getData(waterChart, 'ajax/getWaterData.php');
|
getData(waterChart, 'ajax/getWaterData.php', { sunrise: { FROM: -24, TO: 0 } });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getData(chart, url, sunrise=true) {
|
|
||||||
try {
|
|
||||||
console.log("fetching");
|
|
||||||
const response = await fetch(url);
|
|
||||||
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=-24&TO=0");
|
|
||||||
if (!response2.ok) {
|
|
||||||
console.log("err");
|
|
||||||
throw new Error(`Response status: ${response2.status}`);
|
|
||||||
}
|
|
||||||
chart.options.plugins.annotation.annotations = await response2.json();
|
|
||||||
}
|
|
||||||
chart.update();
|
|
||||||
} 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"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -139,61 +139,14 @@ Chart.defaults.plugins.legend.labels.generateLabels = legendLabels;
|
|||||||
);
|
);
|
||||||
document.addEventListener('readystatechange', function () {
|
document.addEventListener('readystatechange', function () {
|
||||||
if (event.target.readyState === "complete") {
|
if (event.target.readyState === "complete") {
|
||||||
getData(prodChart, 'ajax/getProdData_month.php');
|
getData(prodChart, 'ajax/energyHistory.php?series=prod&range=month');
|
||||||
getData(consChart, 'ajax/getConsData_month.php');
|
getData(consChart, 'ajax/energyHistory.php?series=cons&range=month');
|
||||||
getData(prodChartYear, 'ajax/getProdData_year.php');
|
getData(prodChartYear, 'ajax/energyHistory.php?series=prod&range=year');
|
||||||
getData(consChartYear, 'ajax/getConsData_year.php');
|
getData(consChartYear, 'ajax/energyHistory.php?series=cons&range=year');
|
||||||
getData(prodChartDecade, 'ajax/getProdData_decade.php');
|
getData(prodChartDecade, 'ajax/energyHistory.php?series=prod&range=decade');
|
||||||
getData(consChartDecade, 'ajax/getConsData_decade.php');
|
getData(consChartDecade, 'ajax/energyHistory.php?series=cons&range=decade');
|
||||||
//getData(prodChart, 'ajax/getProdData.php');
|
|
||||||
//getData(foreChart,'ajax/getForecastData.php', false);
|
|
||||||
getStats("Stats-Year","ajax/getStats.php?type=ThisYear");
|
getStats("Stats-Year","ajax/getStats.php?type=ThisYear");
|
||||||
getStats("Stats-Lastyear","ajax/getStats.php?type=LastYear");
|
getStats("Stats-Lastyear","ajax/getStats.php?type=LastYear");
|
||||||
getStats("Stats-Prelastyear","ajax/getStats.php?type=PreLastYear");
|
getStats("Stats-Prelastyear","ajax/getStats.php?type=PreLastYear");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getData(chart, url, sunrise=true) {
|
|
||||||
try {
|
|
||||||
console.log("fetching"+chart);
|
|
||||||
const response = await fetch(url);
|
|
||||||
if (!response.ok) {
|
|
||||||
console.log("err");
|
|
||||||
throw new Error(`Response status: ${response.status}`);
|
|
||||||
}
|
|
||||||
chart.data = await response.json();
|
|
||||||
|
|
||||||
|
|
||||||
chart.update();
|
|
||||||
//chart.options.scales.x.min = chart.data.labels[0]-(chart.data.labels[1]-chart.data.labels[0])/2;
|
|
||||||
//chart.options.scales.x.max = chart.data.labels[chart.data.labels.length-1]+(chart.data.labels[1]-chart.data.labels[0])/2;
|
|
||||||
chart.update();
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error.message);
|
|
||||||
}
|
|
||||||
setTimeout(function () { getData(chart, url, sunrise) }, 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"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -51,205 +51,26 @@ const homeSVG = {
|
|||||||
fillElementArray: function () {
|
fillElementArray: function () {
|
||||||
|
|
||||||
},
|
},
|
||||||
updateValuesMQTT: function (mqttData) {
|
updateValuesMQTT: function (mqttData) {
|
||||||
var htmlNode = document
|
// homeRooms liefert restricted/rooms.php (in home.php eingebettet).
|
||||||
//OG
|
// Jeder Raum bekommt die gleiche Behandlung - Raeume kommen dort dazu,
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Heating"]) != "undefined"){
|
// nicht hier.
|
||||||
if(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Heating"] == "false") htmlNode.getElementById('OG_wozi_heater').setAttribute("display", "none");
|
homeRooms.forEach(function (room) {
|
||||||
else htmlNode.getElementById('OG_wozi_heater').setAttribute("display", "");
|
const values = mqttData["Raumtemp"]?.[room.floor]?.[room.mqtt];
|
||||||
}
|
if (!values) return; // Topic noch nicht empfangen
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["mode"]) != "undefined"){
|
const el = (part) => document.getElementById(room.floor + "_" + part);
|
||||||
if(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["mode"] == "Overheating") htmlNode.getElementById('OG_wozi_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('OG_wozi_buffer').setAttribute("display", "none");
|
if (typeof (values["Heating"]) != "undefined")
|
||||||
}
|
el(room.id + "_heater").setAttribute("display", values["Heating"] == "false" ? "none" : "");
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Set Temp[degC]"]) != "undefined")
|
if (typeof (values["mode"]) != "undefined")
|
||||||
htmlNode.getElementById('OG_pres_wozi').innerHTML = Math.floor(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Set Temp[degC]"])+" °C";
|
el(room.id + "_buffer").setAttribute("display", values["mode"] == "Overheating" ? "" : "none");
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Temp[degC]"]) != "undefined")
|
if (typeof (values["Set Temp[degC]"]) != "undefined")
|
||||||
htmlNode.getElementById('OG_tmp_wozi').innerHTML = mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Temp[degC]"]+" °C";
|
el("pres_" + room.id).innerHTML = Math.floor(values["Set Temp[degC]"]) + "\u2009\u00b0C";
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["rHum[%]"]) != "undefined")
|
if (typeof (values["Temp[degC]"]) != "undefined")
|
||||||
htmlNode.getElementById('OG_hum_wozi').innerHTML = mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["rHum[%]"]+" %rF";
|
el("tmp_" + room.id).innerHTML = values["Temp[degC]"] + "\u2009\u00b0C";
|
||||||
|
if (typeof (values["rHum[%]"]) != "undefined")
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["Heating"]) != "undefined"){
|
el("hum_" + room.id).innerHTML = values["rHum[%]"] + "\u2009%rF";
|
||||||
if(mqttData["Raumtemp"]["OG"]["Bad"]["Heating"] == "false") htmlNode.getElementById('OG_bad_heater').setAttribute("display", "none");
|
});
|
||||||
else htmlNode.getElementById('OG_bad_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["OG"]["Bad"]["mode"] == "Overheating") htmlNode.getElementById('OG_bad_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('OG_bad_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_pres_bad').innerHTML = Math.floor(mqttData["Raumtemp"]["OG"]["Bad"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_tmp_bad').innerHTML = mqttData["Raumtemp"]["OG"]["Bad"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_hum_bad').innerHTML = mqttData["Raumtemp"]["OG"]["Bad"]["rHum[%]"]+" %rF";
|
|
||||||
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Heating"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Heating"] == "false") htmlNode.getElementById('OG_schlafen_heater').setAttribute("display", "none");
|
|
||||||
else htmlNode.getElementById('OG_schlafen_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["mode"] == "Overheating") htmlNode.getElementById('OG_schlafen_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('OG_schlafen_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_pres_schlafen').innerHTML = Math.floor(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_tmp_schlafen').innerHTML = mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_hum_schlafen').innerHTML = mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["rHum[%]"]+" %rF";
|
|
||||||
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["Heating"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["OG"]["KiZi"]["Heating"] == "false") htmlNode.getElementById('OG_kizi_heater').setAttribute("display", "none");
|
|
||||||
else htmlNode.getElementById('OG_kizi_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["OG"]["KiZi"]["mode"] == "Overheating") htmlNode.getElementById('OG_kizi_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('OG_kizi_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_pres_kizi').innerHTML = Math.floor(mqttData["Raumtemp"]["OG"]["KiZi"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_tmp_kizi').innerHTML = mqttData["Raumtemp"]["OG"]["KiZi"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_hum_kizi').innerHTML = mqttData["Raumtemp"]["OG"]["KiZi"]["rHum[%]"]+" %rF";
|
|
||||||
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["Heating"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["OG"]["Buero"]["Heating"] == "false") htmlNode.getElementById('OG_buero_heater').setAttribute("display", "none");
|
|
||||||
else htmlNode.getElementById('OG_buero_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["OG"]["Buero"]["mode"] == "Overheating") htmlNode.getElementById('OG_buero_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('OG_buero_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_pres_buero').innerHTML = Math.floor(mqttData["Raumtemp"]["OG"]["Buero"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_tmp_buero').innerHTML = mqttData["Raumtemp"]["OG"]["Buero"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('OG_hum_buero').innerHTML = mqttData["Raumtemp"]["OG"]["Buero"]["rHum[%]"]+" %rF";
|
|
||||||
|
|
||||||
//EG
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Heating"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Heating"] == "false") htmlNode.getElementById('EG_wozi_heater').setAttribute("display", "none");
|
|
||||||
else htmlNode.getElementById('EG_wozi_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["mode"] == "Overheating") htmlNode.getElementById('EG_wozi_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('EG_wozi_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_pres_wozi').innerHTML = Math.floor(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_tmp_wozi').innerHTML = mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_hum_wozi').innerHTML = mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["rHum[%]"]+" %rF";
|
|
||||||
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["Heating"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["EG"]["Bad"]["Heating"] == "false") htmlNode.getElementById('EG_bad_heater').setAttribute("display", "none");
|
|
||||||
else htmlNode.getElementById('EG_bad_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["EG"]["Bad"]["mode"] == "Overheating") htmlNode.getElementById('EG_bad_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('EG_bad_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_pres_bad').innerHTML = Math.floor(mqttData["Raumtemp"]["EG"]["Bad"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_tmp_bad').innerHTML = mqttData["Raumtemp"]["EG"]["Bad"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_hum_bad').innerHTML = mqttData["Raumtemp"]["EG"]["Bad"]["rHum[%]"]+" %rF";
|
|
||||||
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["Heating"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["EG"]["Schlafen"]["Heating"] == "false") htmlNode.getElementById('EG_schlafen_heater').setAttribute("display", "none");
|
|
||||||
else htmlNode.getElementById('EG_schlafen_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["EG"]["Schlafen"]["mode"] == "Overheating") htmlNode.getElementById('EG_schlafen_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('EG_schlafen_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_pres_schlafen').innerHTML = Math.floor(mqttData["Raumtemp"]["EG"]["Schlafen"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_tmp_schlafen').innerHTML = mqttData["Raumtemp"]["EG"]["Schlafen"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_hum_schlafen').innerHTML = mqttData["Raumtemp"]["EG"]["Schlafen"]["rHum[%]"]+" %rF";
|
|
||||||
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["Heating"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["EG"]["Florian"]["Heating"] == "false") htmlNode.getElementById('EG_kizi_heater').setAttribute("display", "none");
|
|
||||||
else htmlNode.getElementById('EG_kizi_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["EG"]["Florian"]["mode"] == "Overheating") htmlNode.getElementById('EG_kizi_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('EG_kizi_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_pres_kizi').innerHTML = Math.floor(mqttData["Raumtemp"]["EG"]["Florian"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_tmp_kizi').innerHTML = mqttData["Raumtemp"]["EG"]["Florian"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_hum_kizi').innerHTML = mqttData["Raumtemp"]["EG"]["Florian"]["rHum[%]"]+" %rF";
|
|
||||||
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["Heating"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["EG"]["Magdalena"]["Heating"] == "false") htmlNode.getElementById('EG_buero_heater').setAttribute("display", "none");
|
|
||||||
else htmlNode.getElementById('EG_buero_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["EG"]["Magdalena"]["mode"] == "Overheating") htmlNode.getElementById('EG_buero_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('EG_buero_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_pres_buero').innerHTML = Math.floor(mqttData["Raumtemp"]["EG"]["Magdalena"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_tmp_buero').innerHTML = mqttData["Raumtemp"]["EG"]["Magdalena"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('EG_hum_buero').innerHTML = mqttData["Raumtemp"]["EG"]["Magdalena"]["rHum[%]"]+" %rF";
|
|
||||||
//UG
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["Heating"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["UG"]["Kueche"]["Heating"] == "false") htmlNode.getElementById('UG_kueche_heater').setAttribute("display", "none");
|
|
||||||
else htmlNode.getElementById('UG_kueche_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["UG"]["Kueche"]["mode"] == "Overheating") htmlNode.getElementById('UG_kueche_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('UG_kueche_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('UG_pres_kueche').innerHTML = Math.floor(mqttData["Raumtemp"]["UG"]["Kueche"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('UG_tmp_kueche').innerHTML = mqttData["Raumtemp"]["UG"]["Kueche"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('UG_hum_kueche').innerHTML = mqttData["Raumtemp"]["UG"]["Kueche"]["rHum[%]"]+" %rF";
|
|
||||||
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["Heating"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["UG"]["Buero"]["Heating"] == "false") htmlNode.getElementById('UG_buero_heater').setAttribute("display", "none");
|
|
||||||
else htmlNode.getElementById('UG_buero_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["UG"]["Buero"]["mode"] == "Overheating") htmlNode.getElementById('UG_buero_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('UG_buero_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('UG_pres_buero').innerHTML = Math.floor(mqttData["Raumtemp"]["UG"]["Buero"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('UG_tmp_buero').innerHTML = mqttData["Raumtemp"]["UG"]["Buero"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('UG_hum_buero').innerHTML = mqttData["Raumtemp"]["UG"]["Buero"]["rHum[%]"]+" %rF";
|
|
||||||
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["Heating"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["UG"]["Bad"]["Heating"] == "false") htmlNode.getElementById('UG_bad_heater').setAttribute("display", "none");
|
|
||||||
else htmlNode.getElementById('UG_bad_heater').setAttribute("display", "");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["mode"]) != "undefined"){
|
|
||||||
if(mqttData["Raumtemp"]["UG"]["Bad"]["mode"] == "Overheating") htmlNode.getElementById('UG_bad_buffer').setAttribute("display", "");
|
|
||||||
else htmlNode.getElementById('UG_bad_buffer').setAttribute("display", "none");
|
|
||||||
}
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["Set Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('UG_pres_bad').innerHTML = Math.floor(mqttData["Raumtemp"]["UG"]["Bad"]["Set Temp[degC]"])+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["Temp[degC]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('UG_tmp_bad').innerHTML = mqttData["Raumtemp"]["UG"]["Bad"]["Temp[degC]"]+" °C";
|
|
||||||
if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["rHum[%]"]) != "undefined")
|
|
||||||
htmlNode.getElementById('UG_hum_bad').innerHTML = mqttData["Raumtemp"]["UG"]["Bad"]["rHum[%]"]+" %rF";
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -336,13 +157,10 @@ function switchFloor(floor){
|
|||||||
document.addEventListener('readystatechange', function () {
|
document.addEventListener('readystatechange', function () {
|
||||||
if (event.target.readyState === "complete") {
|
if (event.target.readyState === "complete") {
|
||||||
homeMQTT.getMQTT();
|
homeMQTT.getMQTT();
|
||||||
this.getElementById("meteogram").innerHTML = "<iframe src='"+meteogramURL+"' frameborder='0' scrolling=NO' allowtransparency='true' sandbox='allow-same-origin allow-scripts allow-popups allow-popups-to-escape-sandbox' style='width: 100%;height: 500px;border: 0;overflow: hidden;'></iframe><!-- DO NOT REMOVE THIS LINK --><a href='https://www.meteoblue.com/de/wetter/woche/index' target='_blank' rel='noopener'></a>";
|
mountMeteogram();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadingHTML(msg) {
|
|
||||||
return "<div class='m-4'><div class='spinner-border' role='status'><span class='visually-hidden'>Loading...</span></div> " + msg + "</div>"
|
|
||||||
}
|
|
||||||
|
|
||||||
function openModal(heater) {
|
function openModal(heater) {
|
||||||
var contentURL = "./ajax/roomtemp.php?heater="+heater;
|
var contentURL = "./ajax/roomtemp.php?heater="+heater;
|
||||||
@@ -365,21 +183,7 @@ function switchFloor(floor){
|
|||||||
modalBodyElement.innerHTML = html;
|
modalBodyElement.innerHTML = html;
|
||||||
var slider = document.getElementById("modal-slider");
|
var slider = document.getElementById("modal-slider");
|
||||||
var span = document.getElementById("modal-slider-label");
|
var span = document.getElementById("modal-slider-label");
|
||||||
slider.oninput = function () {
|
bindModalSlider(slider, span, value => value + " °C");
|
||||||
sliderPrcnt=(slider.value-10)*5;
|
|
||||||
slider.style.setProperty("--background-size", `${sliderPrcnt}%`);
|
|
||||||
marginValue = sliderPrcnt;
|
|
||||||
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 + " °C";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(typeof(mqttData["Raumtemp"][heaterMQTT[0]][heaterMQTT[1]]["Set Temp[degC]"])!= "undefined")
|
if(typeof(mqttData["Raumtemp"][heaterMQTT[0]][heaterMQTT[1]]["Set Temp[degC]"])!= "undefined")
|
||||||
slider.setAttribute("value",mqttData["Raumtemp"][heaterMQTT[0]][heaterMQTT[1]]["Set Temp[degC]"]);
|
slider.setAttribute("value",mqttData["Raumtemp"][heaterMQTT[0]][heaterMQTT[1]]["Set Temp[degC]"]);
|
||||||
@@ -391,39 +195,3 @@ function switchFloor(floor){
|
|||||||
modalBodyElement.innerHTML += error.message;
|
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){
|
|
||||||
setTimeout(function () { modalEV.hide() }, 700);
|
|
||||||
if(xmlhttp.responseText){
|
|
||||||
alert(xmlhttp.responseText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const form = document.getElementById('modalEV').querySelector('form');
|
|
||||||
post = "";
|
|
||||||
// Get interesting form elements
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -77,7 +77,7 @@ const solarMQTT = {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
}else if(topic == "weatherStation/windDeg"){
|
}else if(topic == "weatherStation/windDeg"){
|
||||||
setTimeout(function () { updateValuesWeather() }, 200); //give the object tree some time to build up and receive all values
|
setTimeout(function () { updateWeatherCards(name => mqttData["weatherStation/" + name]) }, 200); //give the object tree some time to build up and receive all values
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -89,10 +89,54 @@ const solarMQTT = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Die Knoten im eingebetteten Realtime-SVG bleiben ueber die Lebensdauer der
|
||||||
|
// Seite bestehen. updateValuesMQTT fasst 104 davon an - bis zu einmal pro
|
||||||
|
// Sekunde -, deshalb werden sie einmal nachgeschlagen und dann behalten.
|
||||||
|
const svgElements = {};
|
||||||
|
function svgElement(id) {
|
||||||
|
let node = svgElements[id];
|
||||||
|
if (node === undefined) {
|
||||||
|
node = svgElements[id] = document.getElementById(id);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nur schreiben, wenn sich der Wert wirklich geaendert hat. Jeder Schreibzugriff
|
||||||
|
// macht Style und Paint des Elements ungueltig - bei einem gefilterten Element
|
||||||
|
// wird dabei sein Filter neu gerastert. Gemessen waren rund 71 % der Zugriffe
|
||||||
|
// pro Update reine Wiederholungen desselben Werts; die entfallen damit.
|
||||||
|
const letzterWert = new Map();
|
||||||
|
function schreibe(schluessel, wert, anwenden) {
|
||||||
|
const s = String(wert);
|
||||||
|
if (letzterWert.get(schluessel) === s) return;
|
||||||
|
letzterWert.set(schluessel, s);
|
||||||
|
anwenden(s);
|
||||||
|
}
|
||||||
|
// textContent statt innerHTML: setzt einen Textknoten, ohne den HTML-Parser zu bemuehen.
|
||||||
|
function setText(id, wert) { schreibe("t:" + id, wert, s => { svgElement(id).textContent = s; }); }
|
||||||
|
function setHTML(id, markup) { schreibe("h:" + id, markup, s => { svgElement(id).innerHTML = s; }); }
|
||||||
|
function setAttr(id, name, wert) { schreibe("a:" + id + ":" + name, wert, s => { svgElement(id).setAttribute(name, s); }); }
|
||||||
|
function setDisplay(id, wert) { schreibe("d:" + id, wert, s => { svgElement(id).style.display = s; }); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Punktgroesse einer Flusslinie setzen und die Animation anhalten, wenn kein
|
||||||
|
// Fluss anliegt. --w ist der Durchmesser, die CSS-Regel macht daraus den Radius
|
||||||
|
// aller Punkte der Gruppe. will-change nur solange die Gruppe laeuft: es fordert
|
||||||
|
// eine eigene Compositor-Ebene an, und die kostet Speicher.
|
||||||
|
function setFlowWidth(id, width) {
|
||||||
|
const flow = svgElement(id);
|
||||||
|
const sichtbar = Math.abs(width) >= 0.5;
|
||||||
|
flow.style.setProperty("--w", (sichtbar ? Math.abs(width) : 0) + "px");
|
||||||
|
flow.style.animationPlayState = sichtbar ? "running" : "paused";
|
||||||
|
flow.style.willChange = sichtbar ? "transform" : "auto";
|
||||||
|
}
|
||||||
|
|
||||||
const solarSVG = {
|
const solarSVG = {
|
||||||
updateCnt: 99,
|
updateCnt: 99,
|
||||||
|
/** Cache verwerfen - noetig, falls das SVG neu gezeichnet wird. */
|
||||||
fillElementArray: function () {
|
fillElementArray: function () {
|
||||||
|
for (const id in svgElements) delete svgElements[id];
|
||||||
},
|
},
|
||||||
updateValuesMQTT: function (mqttData) {
|
updateValuesMQTT: function (mqttData) {
|
||||||
|
|
||||||
@@ -143,16 +187,15 @@ const solarSVG = {
|
|||||||
common = 0;
|
common = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var htmlNode = document
|
setAttr('consumerArc', "d", describeArc(100, 100, 95, 0, Math.round(-cons / angleFactor)));
|
||||||
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)));
|
setAttr("ogArc", "d", describeArc(100, 100, 95, 0, Math.round(-og / angleFactor)));
|
||||||
htmlNode.getElementById("consumerText").innerHTML = powerToString(-cons);
|
setText("consumerText", powerToString(-cons));
|
||||||
|
|
||||||
htmlNode.getElementById("consumerTextAllg").innerHTML = "Gemein: "+powerToString(common);
|
setText("consumerTextAllg", "Gemein: "+powerToString(common));
|
||||||
|
|
||||||
if (evPower > 0) {
|
if (evPower > 0) {
|
||||||
htmlNode.getElementById("evCharge").style.display = "";
|
setDisplay("evCharge", "");
|
||||||
if (carRemChrg > -1) {
|
if (carRemChrg > -1) {
|
||||||
var today = new Date();
|
var today = new Date();
|
||||||
today.setMinutes(today.getMinutes() + carRemChrg);
|
today.setMinutes(today.getMinutes() + carRemChrg);
|
||||||
@@ -162,31 +205,31 @@ const solarSVG = {
|
|||||||
h = "0" + h;
|
h = "0" + h;
|
||||||
if (m < 10)
|
if (m < 10)
|
||||||
m = "0" + m;
|
m = "0" + m;
|
||||||
htmlNode.getElementById("evRemText").innerHTML = h + ":" + m
|
setText("evRemText", h + ":" + m);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("evRemText").innerHTML = "";
|
setText("evRemText", "");
|
||||||
}
|
}
|
||||||
htmlNode.getElementById("ogText").innerHTML = powerToString(-og);
|
setText("ogText", powerToString(-og));
|
||||||
htmlNode.getElementById("egText").innerHTML = powerToString(eg);
|
setText("egText", powerToString(eg));
|
||||||
htmlNode.getElementById("ugText").innerHTML = powerToString(ug);
|
setText("ugText", powerToString(ug));
|
||||||
htmlNode.getElementById("pvText").innerHTML = powerToString(pv);
|
setText("pvText", powerToString(pv));
|
||||||
htmlNode.getElementById("pv1txt").innerHTML = powerToString(pv1);
|
setText("pv1txt", powerToString(pv1));
|
||||||
htmlNode.getElementById("pv2txt").innerHTML = powerToString(pv2);
|
setText("pv2txt", powerToString(pv2));
|
||||||
htmlNode.getElementById("pv3txt").innerHTML = powerToString(pv3);
|
setText("pv3txt", powerToString(pv3));
|
||||||
htmlNode.getElementById("il1txt").innerHTML = Math.round(i_l1evu * 10) / 10 + " A"
|
setText("il1txt", Math.round(i_l1evu * 10) / 10 + " A");
|
||||||
htmlNode.getElementById("il2txt").innerHTML = Math.round(i_l2evu * 10) / 10 + " A"
|
setText("il2txt", Math.round(i_l2evu * 10) / 10 + " A");
|
||||||
htmlNode.getElementById("il3txt").innerHTML = Math.round(i_l3evu * 10) / 10 + " A"
|
setText("il3txt", Math.round(i_l3evu * 10) / 10 + " A");
|
||||||
htmlNode.getElementById("batText").innerHTML = powerToString(pbatt);
|
setText("batText", powerToString(pbatt));
|
||||||
htmlNode.getElementById("heatText").innerHTML = powerToString(Pheat);
|
setText("heatText", powerToString(Pheat));
|
||||||
htmlNode.getElementById("evText").innerHTML = powerToString(evPower * 1000);
|
setText("evText", powerToString(evPower * 1000));
|
||||||
htmlNode.getElementById("evTextOG").innerHTML = powerToString(evPowerOG * 1000);
|
setText("evTextOG", powerToString(evPowerOG * 1000));
|
||||||
htmlNode.getElementById("genText").innerHTML = "Autarkie: " + Math.round(aut) + " %";
|
setText("genText", "Autarkie: " + Math.round(aut) + " %");
|
||||||
htmlNode.getElementById("genInfoText").innerHTML = "Wirkungsgrad: " + Math.round(eff) + " %";// powerToString(p_wr);
|
setText("genInfoText", "Wirkungsgrad: " + Math.round(eff) + " %");// powerToString(p_wr);
|
||||||
htmlNode.getElementById("gridText").innerHTML = powerToString(grid);
|
setText("gridText", powerToString(grid));
|
||||||
|
|
||||||
for (i = 0; i < pvn.length; i++) {
|
for (i = 0; i < pvn.length; i++) {
|
||||||
htmlNode.getElementById("det_pv" + i + "P").innerHTML = powerToString(pvn[i]);
|
setText("det_pv" + i + "P", powerToString(pvn[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
tttext = ""
|
tttext = ""
|
||||||
@@ -204,127 +247,126 @@ const solarSVG = {
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlNode.getElementById("invList").innerHTML = tttext
|
setHTML("invList", tttext);
|
||||||
htmlNode.getElementById("egArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(eg / angleFactor)));
|
setAttr("egArc", "d", describeArc(100, 100, 95, 0, Math.round(eg / angleFactor)));
|
||||||
htmlNode.getElementById("ugArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(ug / angleFactor)));
|
setAttr("ugArc", "d", describeArc(100, 100, 95, 0, Math.round(ug / angleFactor)));
|
||||||
htmlNode.getElementById("pvArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(pv1 / angleFactor)));
|
setAttr("pvArc", "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)));
|
setAttr("pv2Arc", "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)));
|
setAttr("pv3Arc", "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 (pbatt < 0) {
|
||||||
if (limbatt < 100) {
|
if (limbatt < 100) {
|
||||||
htmlNode.getElementById("charge").style.display = "none";
|
setDisplay("charge", "none");
|
||||||
htmlNode.getElementById("batLim").style.display = "";
|
setDisplay("batLim", "");
|
||||||
htmlNode.getElementById("batLimText").innerHTML = Math.round(limbatt) + "%";
|
setText("batLimText", Math.round(limbatt) + "%");
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("charge").style.display = "";
|
setDisplay("charge", "");
|
||||||
htmlNode.getElementById("batLim").style.display = "none";
|
setDisplay("batLim", "none");
|
||||||
}
|
}
|
||||||
htmlNode.getElementById("batArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(-pbatt / angleFactor)));
|
setAttr("batArc", "d", describeArc(100, 100, 95, 0, Math.round(-pbatt / angleFactor)));
|
||||||
htmlNode.getElementById("battani").setAttribute("class", "stream-rev");
|
setAttr("battani", "class", "stream-rev");
|
||||||
htmlNode.getElementById("battani").setAttribute("stroke-width", 55 * (1 - Math.exp(pbatt / 2000)));
|
setFlowWidth("battani", 55 * (1 - Math.exp(pbatt / 2000)));
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("charge").style.display = "none";
|
setDisplay("charge", "none");
|
||||||
htmlNode.getElementById("batLim").style.display = "none";
|
setDisplay("batLim", "none");
|
||||||
htmlNode.getElementById("batArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(pbatt / angleFactor)));
|
setAttr("batArc", "d", describeArc(100, 100, 95, 0, Math.round(pbatt / angleFactor)));
|
||||||
htmlNode.getElementById("battani").setAttribute("class", "stream");
|
setAttr("battani", "class", "stream");
|
||||||
htmlNode.getElementById("battani").setAttribute("stroke-width", 55 * (1 - Math.exp(-pbatt / 2000)));
|
setFlowWidth("battani", 55 * (1 - Math.exp(-pbatt / 2000)));
|
||||||
}
|
}
|
||||||
htmlNode.getElementById("batChargeState").setAttribute("y", (100 - soc) + "%");
|
setAttr("batChargeState", "y", (100 - soc) + "%");
|
||||||
//htmlNode.getElementById("heatChargeState").setAttribute("y", 100 - ((((puffO + puffM) / 2) - 30) * 1.66) + "%");
|
//setAttr("heatChargeState", "y", 100 - ((((puffO + puffM) / 2) - 30) * 1.66) + "%");
|
||||||
htmlNode.getElementById('tmpH').setAttribute("stop-color", assignColor("#2389BA", "#BA3B23", 20, 80, puffO));
|
setAttr('tmpH', "stop-color", assignColor("#2389BA", "#BA3B23", 20, 80, puffO));
|
||||||
htmlNode.getElementById('tmpM').setAttribute("stop-color", assignColor("#2389BA", "#BA3B23", 20, 80, puffM));
|
setAttr('tmpM', "stop-color", assignColor("#2389BA", "#BA3B23", 20, 80, puffM));
|
||||||
htmlNode.getElementById('tmpL').setAttribute("stop-color", assignColor("#2389BA", "#BA3B23", 20, 80, puffU));
|
setAttr('tmpL', "stop-color", assignColor("#2389BA", "#BA3B23", 20, 80, puffU));
|
||||||
htmlNode.getElementById("batSOC").innerHTML = soc + " %";
|
setText("batSOC", soc + " %");
|
||||||
htmlNode.getElementById("evArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(evPower * 2000 / angleFactor)));
|
setAttr("evArc", "d", describeArc(100, 100, 95, 0, Math.round(evPower * 2000 / angleFactor)));
|
||||||
htmlNode.getElementById("evChargeState").setAttribute("y", (100 - evsoc) + "%");
|
setAttr("evChargeState", "y", (100 - evsoc) + "%");
|
||||||
htmlNode.getElementById("evSOC").innerHTML = evsoc + " %";
|
setText("evSOC", evsoc + " %");
|
||||||
htmlNode.getElementById("evFuel").innerHTML = fuelev + " %";
|
setText("evFuel", fuelev + " %");
|
||||||
|
|
||||||
htmlNode.getElementById("heatArc").setAttribute("d", describeArc(100, 100, 95, 0, Math.round(Pheat / sixkWangleFactor)));
|
setAttr("heatArc", "d", describeArc(100, 100, 95, 0, Math.round(Pheat / sixkWangleFactor)));
|
||||||
htmlNode.getElementById("heatUp").innerHTML = Math.round(puffO * 10) / 10 + " °C";
|
setText("heatUp", Math.round(puffO * 10) / 10 + " °C");
|
||||||
htmlNode.getElementById("heatDown").innerHTML = Math.round(puffM * 10) / 10 + " °C";
|
setText("heatDown", Math.round(puffM * 10) / 10 + " °C");
|
||||||
|
|
||||||
if (evlock == false) {
|
if (evlock == false) {
|
||||||
htmlNode.getElementById("evLock").style.display = "none";
|
setDisplay("evLock", "none");
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("evLock").style.display = "";
|
setDisplay("evLock", "");
|
||||||
}
|
}
|
||||||
if (heatMode == "eco") {
|
if (heatMode == "eco") {
|
||||||
htmlNode.getElementById("heatEco").style.display = "";
|
setDisplay("heatEco", "");
|
||||||
htmlNode.getElementById("heatDefault").style.display = "none";
|
setDisplay("heatDefault", "none");
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("heatEco").style.display = "none";
|
setDisplay("heatEco", "none");
|
||||||
htmlNode.getElementById("heatDefault").style.display = "";
|
setDisplay("heatDefault", "");
|
||||||
}
|
}
|
||||||
if (evMode == "Eco") {
|
if (evMode == "Eco") {
|
||||||
htmlNode.getElementById("evEco").style.display = "";
|
setDisplay("evEco", "");
|
||||||
htmlNode.getElementById("evNextTrip").style.display = "none";
|
setDisplay("evNextTrip", "none");
|
||||||
htmlNode.getElementById("evDefault").style.display = "none";
|
setDisplay("evDefault", "none");
|
||||||
} else if (evMode == "Next Trip") {
|
} else if (evMode == "Next Trip") {
|
||||||
htmlNode.getElementById("evEco").style.display = "none";
|
setDisplay("evEco", "none");
|
||||||
htmlNode.getElementById("evNextTrip").style.display = "";
|
setDisplay("evNextTrip", "");
|
||||||
htmlNode.getElementById("evDefault").style.display = "none";
|
setDisplay("evDefault", "none");
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("evEco").style.display = "none";
|
setDisplay("evEco", "none");
|
||||||
htmlNode.getElementById("evNextTrip").style.display = "none";
|
setDisplay("evNextTrip", "none");
|
||||||
htmlNode.getElementById("evDefault").style.display = "";
|
setDisplay("evDefault", "");
|
||||||
}
|
}
|
||||||
if (heatOG) {
|
if (heatOG) {
|
||||||
htmlNode.getElementById("heatOG").style.display = "";
|
setDisplay("heatOG", "");
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("heatOG").style.display = "none";
|
setDisplay("heatOG", "none");
|
||||||
}
|
}
|
||||||
if (heatEG) {
|
if (heatEG) {
|
||||||
htmlNode.getElementById("heatEG").style.display = "";
|
setDisplay("heatEG", "");
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("heatEG").style.display = "none";
|
setDisplay("heatEG", "none");
|
||||||
}
|
}
|
||||||
if (plugev != "no car") {
|
if (plugev != "no car") {
|
||||||
htmlNode.getElementById("evPlug").style.display = "";
|
setDisplay("evPlug", "");
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("evPlug").style.display = "none";
|
setDisplay("evPlug", "none");
|
||||||
}
|
}
|
||||||
if (evModeOG == "Eco") {
|
if (evModeOG == "Eco") {
|
||||||
htmlNode.getElementById("evEcoOG").style.display = "";
|
setDisplay("evEcoOG", "");
|
||||||
htmlNode.getElementById("evNextTripOG").style.display = "none";
|
setDisplay("evNextTripOG", "none");
|
||||||
htmlNode.getElementById("evDefaultOG").style.display = "none";
|
setDisplay("evDefaultOG", "none");
|
||||||
} else if (evModeOG == "Next Trip") {
|
} else if (evModeOG == "Next Trip") {
|
||||||
htmlNode.getElementById("evEcoOG").style.display = "none";
|
setDisplay("evEcoOG", "none");
|
||||||
htmlNode.getElementById("evNextTripOG").style.display = "";
|
setDisplay("evNextTripOG", "");
|
||||||
htmlNode.getElementById("evDefaultOG").style.display = "none";
|
setDisplay("evDefaultOG", "none");
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("evEcoOG").style.display = "none";
|
setDisplay("evEcoOG", "none");
|
||||||
htmlNode.getElementById("evNextTripOG").style.display = "none";
|
setDisplay("evNextTripOG", "none");
|
||||||
htmlNode.getElementById("evDefaultOG").style.display = "";
|
setDisplay("evDefaultOG", "");
|
||||||
}
|
}
|
||||||
if (evPlugOG > 0) {
|
if (evPlugOG > 0) {
|
||||||
htmlNode.getElementById("evPlugOG").style.display = "";
|
setDisplay("evPlugOG", "");
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("evPlugOG").style.display = "none";
|
setDisplay("evPlugOG", "none");
|
||||||
}
|
}
|
||||||
if (grid < 0) {
|
if (grid < 0) {
|
||||||
htmlNode.getElementById("gridArc").setAttribute("d", describeArc(100, 100, 95, 0, -grid / angleFactor));
|
setAttr("gridArc", "d", describeArc(100, 100, 95, 0, -grid / angleFactor));
|
||||||
htmlNode.getElementById("consGridani").setAttribute("class", "stream-rev");
|
setAttr("consGridani", "class", "stream-rev");
|
||||||
htmlNode.getElementById("consGridani").setAttribute("stroke-width", 55 * (1 - Math.exp(grid / 2000)));
|
setFlowWidth("consGridani", 55 * (1 - Math.exp(grid / 2000)));
|
||||||
} else {
|
} else {
|
||||||
htmlNode.getElementById("gridArc").setAttribute("d", describeArc(100, 100, 95, 0, grid / angleFactor));
|
setAttr("gridArc", "d", describeArc(100, 100, 95, 0, grid / angleFactor));
|
||||||
htmlNode.getElementById("consGridani").setAttribute("class", "stream");
|
setAttr("consGridani", "class", "stream");
|
||||||
htmlNode.getElementById("consGridani").setAttribute("stroke-width", 55 * (1 - Math.exp(-grid / 2000)));
|
setFlowWidth("consGridani", 55 * (1 - Math.exp(-grid / 2000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlNode.getElementById("consEVani").setAttribute("stroke-width", 55 * (1 - Math.exp(-evPower)));
|
setFlowWidth("consEVani", 55 * (1 - Math.exp(-evPower)));
|
||||||
htmlNode.getElementById("consEVOGani").setAttribute("stroke-width", 55 * (1 - Math.exp(-evPowerOG)));
|
setFlowWidth("consEVOGani", 55 * (1 - Math.exp(-evPowerOG)));
|
||||||
htmlNode.getElementById("consOGani").setAttribute("stroke-width", 55 * (1 - Math.exp(og / 2000)));
|
setFlowWidth("consOGani", 55 * (1 - Math.exp(og / 2000)));
|
||||||
|
|
||||||
htmlNode.getElementById("consUGani").setAttribute("stroke-width", 55 * (1 - Math.exp( -ug / 2000)));
|
setFlowWidth("consUGani", 55 * (1 - Math.exp( -ug / 2000)));
|
||||||
|
|
||||||
htmlNode.getElementById("consHeatAni").setAttribute("stroke-width", 55 * (1 - Math.exp(-Pheat / 2000)));
|
setFlowWidth("consHeatAni", 55 * (1 - Math.exp(-Pheat / 2000)));
|
||||||
htmlNode.getElementById("consAni").setAttribute("stroke-width", 55 * (1 - Math.exp(cons / 2000)));
|
setFlowWidth("consAni", 55 * (1 - Math.exp(cons / 2000)));
|
||||||
htmlNode.getElementById("consEGani").setAttribute("stroke-width", 55 * (1 - Math.exp(-eg / 2000)));
|
setFlowWidth("consEGani", 55 * (1 - Math.exp(-eg / 2000)));
|
||||||
htmlNode.getElementById("pvani").setAttribute("stroke-width", 55 * (1 - Math.exp(-pv / 2000)));
|
setFlowWidth("pvani", 55 * (1 - Math.exp(-pv / 2000)));
|
||||||
htmlNode.getElementById("pvani");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,6 +514,7 @@ var chartSettings = {
|
|||||||
var mqttData = {};
|
var mqttData = {};
|
||||||
var timeFrom = -24;
|
var timeFrom = -24;
|
||||||
var timeTo = 12;
|
var timeTo = 12;
|
||||||
|
const dayRange = () => ({ FROM: timeFrom, TO: timeTo });
|
||||||
const consChart = new Chart(
|
const consChart = new Chart(
|
||||||
document.querySelector('#consumption-chart'),
|
document.querySelector('#consumption-chart'),
|
||||||
Object.assign({}, chartSettings)
|
Object.assign({}, chartSettings)
|
||||||
@@ -487,8 +530,8 @@ var chartSettings = {
|
|||||||
);
|
);
|
||||||
|
|
||||||
function updateCharts(){
|
function updateCharts(){
|
||||||
getData(consChart, 'ajax/getConsData.php',true,false,false);
|
getData(consChart, 'ajax/getConsData.php', { params: dayRange, sunrise: true, autoUpdate: false, updateMode: "none" });
|
||||||
getData(prodChart, 'ajax/getProdData.php',true,false,false);
|
getData(prodChart, 'ajax/getProdData.php', { params: dayRange, sunrise: true, autoUpdate: false, updateMode: "none" });
|
||||||
}
|
}
|
||||||
|
|
||||||
function prevDay(){
|
function prevDay(){
|
||||||
@@ -531,29 +574,16 @@ var chartSettings = {
|
|||||||
document.addEventListener('readystatechange', function () {
|
document.addEventListener('readystatechange', function () {
|
||||||
if (event.target.readyState === "complete") {
|
if (event.target.readyState === "complete") {
|
||||||
solarMQTT.getMQTT();
|
solarMQTT.getMQTT();
|
||||||
getData(consChart, 'ajax/getConsData.php');
|
getData(consChart, 'ajax/getConsData.php', { params: dayRange, sunrise: true, updateMode: "none" });
|
||||||
getData(prodChart, 'ajax/getProdData.php');
|
getData(prodChart, 'ajax/getProdData.php', { params: dayRange, sunrise: true, updateMode: "none" });
|
||||||
getData(foreChart,'ajax/getForecastData.php', false);
|
getData(foreChart, 'ajax/getForecastData.php', { params: dayRange, updateMode: "none" });
|
||||||
getStats("Stats-Year","ajax/getStats.php?type=ThisYear");
|
getStats("Stats-Year","ajax/getStats.php?type=ThisYear");
|
||||||
solarSVG.fillElementArray();
|
solarSVG.fillElementArray();
|
||||||
this.getElementById("meteogram").innerHTML = "<iframe src='"+meteogramURL+"' frameborder='0' scrolling=NO' allowtransparency='true' sandbox='allow-same-origin allow-scripts allow-popups allow-popups-to-escape-sandbox' style='width: 100%;height: 500px;border: 0;overflow: hidden;'></iframe><!-- DO NOT REMOVE THIS LINK --><a href='https://www.meteoblue.com/de/wetter/woche/index' target='_blank' rel='noopener'></a>";
|
mountMeteogram();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
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 "<div class='m-4'><div class='spinner-border' role='status'><span class='visually-hidden'>Loading...</span></div> " + msg + "</div>"
|
|
||||||
}
|
|
||||||
|
|
||||||
function openModal(type) {
|
function openModal(type) {
|
||||||
document.getElementById("modalSaveBtn").style.display = type === "watering" ? "none" : "";
|
document.getElementById("modalSaveBtn").style.display = type === "watering" ? "none" : "";
|
||||||
@@ -600,20 +630,7 @@ var chartSettings = {
|
|||||||
var span = document.getElementById("modal-slider-label");
|
var span = document.getElementById("modal-slider-label");
|
||||||
switch(type){
|
switch(type){
|
||||||
case "CarEG":
|
case "CarEG":
|
||||||
slider.oninput = function () {
|
bindModalSlider(slider, span, value => value + "%");
|
||||||
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").addEventListener("click", submitFormAjax);
|
||||||
document.getElementById("evStart/Stop").contentURL = contentURL;
|
document.getElementById("evStart/Stop").contentURL = contentURL;
|
||||||
mode = new TextDecoder().decode(mqttData["wattpilot/properties/lmo/state"]);
|
mode = new TextDecoder().decode(mqttData["wattpilot/properties/lmo/state"]);
|
||||||
@@ -636,20 +653,7 @@ var chartSettings = {
|
|||||||
else if (amp == "6") { document.getElementById("EV_6A").click(); }
|
else if (amp == "6") { document.getElementById("EV_6A").click(); }
|
||||||
break;
|
break;
|
||||||
case "CarOG":
|
case "CarOG":
|
||||||
slider.oninput = function () {
|
bindModalSlider(slider, span, value => value + "%");
|
||||||
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").addEventListener("click", submitFormAjax);
|
||||||
document.getElementById("evStart/Stop").contentURL = contentURL;
|
document.getElementById("evStart/Stop").contentURL = contentURL;
|
||||||
mode = mqttData["go-eCharger/270003/lmo"];
|
mode = mqttData["go-eCharger/270003/lmo"];
|
||||||
@@ -671,24 +675,7 @@ var chartSettings = {
|
|||||||
else if (amp == "6") { document.getElementById("EV_6A").click(); }
|
else if (amp == "6") { document.getElementById("EV_6A").click(); }
|
||||||
break;
|
break;
|
||||||
case "heater":
|
case "heater":
|
||||||
slider.oninput = function () {
|
bindModalSlider(slider, span, value => value == 0 ? "Automatik" : (value / 10) + " kW");
|
||||||
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"){
|
if(mqttData["solarManager/heatMode"] == "eco"){
|
||||||
document.getElementById("modal-slider").value = 0;
|
document.getElementById("modal-slider").value = 0;
|
||||||
}else{
|
}else{
|
||||||
@@ -744,7 +731,8 @@ var chartSettings = {
|
|||||||
const updateButton = () => {
|
const updateButton = () => {
|
||||||
const zone = wateringZones[button.dataset.wateringZone];
|
const zone = wateringZones[button.dataset.wateringZone];
|
||||||
const state = wateringLabel(zone.topic, zone.valve);
|
const state = wateringLabel(zone.topic, zone.valve);
|
||||||
button.textContent = state === "aus" ? "Ein" : "Aus";
|
const beschriftung = state === "aus" ? "Ein" : "Aus";
|
||||||
|
if (button.textContent !== beschriftung) button.textContent = beschriftung;
|
||||||
button.classList.toggle("btn-success", state === "aus");
|
button.classList.toggle("btn-success", state === "aus");
|
||||||
button.classList.toggle("btn-danger", state !== "aus");
|
button.classList.toggle("btn-danger", state !== "aus");
|
||||||
};
|
};
|
||||||
@@ -774,14 +762,27 @@ var chartSettings = {
|
|||||||
updateWateringStatus();
|
updateWateringStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Die Anzeige laeuft im Sekundentakt, die Nutzlasten aendern sich aber nur,
|
||||||
|
// wenn eine neue MQTT-Nachricht kommt. messageReceived legt dabei jedes Mal
|
||||||
|
// ein neues Buffer-Objekt ab - der Identitaetsvergleich reicht also als
|
||||||
|
// Gueltigkeitspruefung, ein Invalidieren von Hand braucht es nicht.
|
||||||
|
const wateringJsonCache = {};
|
||||||
|
const wateringDecoder = new TextDecoder();
|
||||||
|
|
||||||
function wateringJson(topic) {
|
function wateringJson(topic) {
|
||||||
const value = mqttData[topic];
|
const value = mqttData[topic];
|
||||||
if (!value) return null;
|
if (!value) return null;
|
||||||
|
const cached = wateringJsonCache[topic];
|
||||||
|
if (cached && cached.raw === value) return cached.parsed;
|
||||||
|
|
||||||
|
let parsed = null;
|
||||||
try {
|
try {
|
||||||
return JSON.parse(typeof value === "string" ? value : new TextDecoder().decode(value));
|
parsed = JSON.parse(typeof value === "string" ? value : wateringDecoder.decode(value));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return null;
|
parsed = null;
|
||||||
}
|
}
|
||||||
|
wateringJsonCache[topic] = { raw: value, parsed: parsed };
|
||||||
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
function wateringHistory(topic, valve) {
|
function wateringHistory(topic, valve) {
|
||||||
@@ -872,15 +873,24 @@ var chartSettings = {
|
|||||||
return !!(status && status.would_water && !status.watered_recently);
|
return !!(status && status.would_water && !status.watered_recently);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Konstante Tabellen - stehen ausserhalb, damit der Sekundentakt sie nicht
|
||||||
|
// jedes Mal neu aufbaut.
|
||||||
|
const wateringIndicators = [
|
||||||
|
["wateringFrontStatus", "wateringFrontIcon", "Vorn", "Gartenwasser/vorn", 6, "garten_vorn"],
|
||||||
|
["wateringTroughStatus", "wateringTroughIcon", "Tröge", "Gartenwasser/vorn", 1, "troege"],
|
||||||
|
["wateringBedsStatus", "wateringBedsIcon", "Beete", "Gartenwasser/hinten", 6, "hochbeete"]
|
||||||
|
];
|
||||||
|
const wateringHistoryRows = [
|
||||||
|
["troughs", "Gartenwasser/vorn", 1],
|
||||||
|
["frontGarden", "Gartenwasser/vorn", 6],
|
||||||
|
["raisedBeds", "Gartenwasser/hinten", 6]
|
||||||
|
];
|
||||||
|
|
||||||
function updateWateringStatus() {
|
function updateWateringStatus() {
|
||||||
const indicators = [
|
// Die Anzeigen liegen im Realtime-SVG und bleiben bestehen -> svgElement.
|
||||||
["wateringFrontStatus", "wateringFrontIcon", "Vorn", "Gartenwasser/vorn", 6, "garten_vorn"],
|
wateringIndicators.forEach(([statusId, iconId, name, topic, valve, autoZoneKey]) => {
|
||||||
["wateringTroughStatus", "wateringTroughIcon", "Tröge", "Gartenwasser/vorn", 1, "troege"],
|
const status = svgElement(statusId);
|
||||||
["wateringBedsStatus", "wateringBedsIcon", "Beete", "Gartenwasser/hinten", 6, "hochbeete"]
|
const icon = svgElement(iconId);
|
||||||
];
|
|
||||||
indicators.forEach(([statusId, iconId, name, topic, valve, autoZoneKey]) => {
|
|
||||||
const status = document.getElementById(statusId);
|
|
||||||
const icon = document.getElementById(iconId);
|
|
||||||
if (!status || !icon) return;
|
if (!status || !icon) return;
|
||||||
const state = wateringLabel(topic, valve);
|
const state = wateringLabel(topic, valve);
|
||||||
const planned = state === "aus" && wateringAutoPlanned(autoZoneKey);
|
const planned = state === "aus" && wateringAutoPlanned(autoZoneKey);
|
||||||
@@ -889,16 +899,14 @@ var chartSettings = {
|
|||||||
document.querySelectorAll("[data-watering-toggle]").forEach((button) => {
|
document.querySelectorAll("[data-watering-toggle]").forEach((button) => {
|
||||||
const zone = wateringZones[button.dataset.wateringZone];
|
const zone = wateringZones[button.dataset.wateringZone];
|
||||||
const state = wateringLabel(zone.topic, zone.valve);
|
const state = wateringLabel(zone.topic, zone.valve);
|
||||||
button.textContent = state === "aus" ? "Ein" : "Aus";
|
const beschriftung = state === "aus" ? "Ein" : "Aus";
|
||||||
|
if (button.textContent !== beschriftung) button.textContent = beschriftung;
|
||||||
button.classList.toggle("btn-success", state === "aus");
|
button.classList.toggle("btn-success", state === "aus");
|
||||||
button.classList.toggle("btn-danger", state !== "aus");
|
button.classList.toggle("btn-danger", state !== "aus");
|
||||||
});
|
});
|
||||||
document.querySelectorAll("[data-watering-auto-toggle]").forEach(updateWateringAutoButton);
|
document.querySelectorAll("[data-watering-auto-toggle]").forEach(updateWateringAutoButton);
|
||||||
[
|
// Die Modal-Elemente werden bei jedem Oeffnen neu erzeugt -> nicht cachen.
|
||||||
["troughs", "Gartenwasser/vorn", 1],
|
wateringHistoryRows.forEach(([zone, topic, valve]) => {
|
||||||
["frontGarden", "Gartenwasser/vorn", 6],
|
|
||||||
["raisedBeds", "Gartenwasser/hinten", 6]
|
|
||||||
].forEach(([zone, topic, valve]) => {
|
|
||||||
const history = wateringHistory(topic, valve);
|
const history = wateringHistory(topic, valve);
|
||||||
const dateElement = document.querySelector(`[data-watering-last='${zone}']`);
|
const dateElement = document.querySelector(`[data-watering-last='${zone}']`);
|
||||||
const durationElement = document.querySelector(`[data-watering-duration='${zone}']`);
|
const durationElement = document.querySelector(`[data-watering-duration='${zone}']`);
|
||||||
@@ -923,132 +931,29 @@ var chartSettings = {
|
|||||||
// "Aus" bleibt bei nicht geplant stehen; bei geplant ersetzt die
|
// "Aus" bleibt bei nicht geplant stehen; bei geplant ersetzt die
|
||||||
// Stoppuhr (U+23F1, ohne Emoji-Variationsselektor -> einfarbig, folgt
|
// Stoppuhr (U+23F1, ohne Emoji-Variationsselektor -> einfarbig, folgt
|
||||||
// der Icon-Farbe) den Text, um Platz auf der textPath zu sparen.
|
// der Icon-Farbe) den Text, um Platz auf der textPath zu sparen.
|
||||||
status.textContent = state === "aus" ? (planned ? "⏱" : "Aus") : state;
|
// Laeuft im Sekundentakt, aendert sich aber selten - ohne Pruefung
|
||||||
|
// wuerde jede Sekunde derselbe Wert geschrieben und das Icon samt
|
||||||
|
// Filter neu gezeichnet.
|
||||||
|
const text = state === "aus" ? (planned ? "⏱" : "Aus") : state;
|
||||||
|
if (status.textContent !== text) status.textContent = text;
|
||||||
// Geplant-Blau ("#3A6292") entspricht dem Wassertropfen-Icon (id="water").
|
// Geplant-Blau ("#3A6292") entspricht dem Wassertropfen-Icon (id="water").
|
||||||
const color = state !== "aus" ? (paused ? "#ffc107" : "#20c997") : planned ? "#3A6292" : "#6c757d";
|
const color = state !== "aus" ? (paused ? "#ffc107" : "#20c997") : planned ? "#3A6292" : "#6c757d";
|
||||||
icon.setAttribute("color", color);
|
if (icon.getAttribute("color") !== color) {
|
||||||
icon.setAttribute("fill", color);
|
icon.setAttribute("color", color);
|
||||||
icon.style.color = color;
|
icon.setAttribute("fill", color);
|
||||||
icon.querySelector("title").textContent = name + ": " + (state === "aus" && planned ? "Aus (Automatik heute noch geplant)" : state);
|
icon.style.color = color;
|
||||||
|
}
|
||||||
|
const titel = name + ": " + (state === "aus" && planned ? "Aus (Automatik heute noch geplant)" : state);
|
||||||
|
const titelKnoten = icon.querySelector("title");
|
||||||
|
if (titelKnoten.textContent !== titel) titelKnoten.textContent = titel;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.setInterval(updateWateringStatus, 1000);
|
window.setInterval(updateWateringStatus, 1000);
|
||||||
|
|
||||||
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'];
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
|
||||||
var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
|
var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
|
||||||
@@ -1090,29 +995,23 @@ var chartSettings = {
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
function describeArc(x, y, radius, startAngle, endAngle) {
|
function describeArc(x, y, radius, startAngle, endAngle) {
|
||||||
if (endAngle > 288) {
|
if (endAngle > 288) {
|
||||||
endAngle = 288;
|
endAngle = 288;
|
||||||
|
}
|
||||||
|
// Auf volle Grad runden: bei Radius 95 ist ein Grad rund 1,7 Einheiten,
|
||||||
|
// feiner sieht niemand. Dafuer bleibt das d-Attribut bei kleinen
|
||||||
|
// Schwankungen unveraendert und setAttr unterdrueckt den Schreibvorgang -
|
||||||
|
// sonst laesst jeder Zappler den Bogen samt Filter neu zeichnen.
|
||||||
|
startAngle = Math.round(startAngle);
|
||||||
|
endAngle = Math.round(endAngle);
|
||||||
|
var start = polarToCartesian(x, y, radius, endAngle);
|
||||||
|
var end = polarToCartesian(x, y, radius, startAngle);
|
||||||
|
var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
|
||||||
|
// zwei Nachkommastellen genuegen und halten das Attribut kurz
|
||||||
|
var rnd = (v) => Math.round(v * 100) / 100;
|
||||||
|
return [
|
||||||
|
"M", rnd(start.x), rnd(start.y),
|
||||||
|
"A", radius, radius, 0, largeArcFlag, 0, rnd(end.x), rnd(end.y)
|
||||||
|
].join(" ");
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Wetterseite: Messwerte der eigenen Wetterstation und das Meteogramm.
|
||||||
|
* Die Anzeige selbst steckt in updateWeatherCards() / mountMeteogram()
|
||||||
|
* in common.js, hier bleibt nur die MQTT-Anbindung.
|
||||||
|
*/
|
||||||
|
var mqttData = {};
|
||||||
|
|
||||||
|
const weatherMQTT = {
|
||||||
|
getMQTT: function () {
|
||||||
|
const client = mqtt.connect("wss://mqtt.nas.el-wa.org:443", { rejectUnauthorized: false });
|
||||||
|
|
||||||
|
client.on("connect", function () {
|
||||||
|
client.subscribe("weatherStation/#");
|
||||||
|
});
|
||||||
|
client.on("message", function (topic, message) {
|
||||||
|
mqttData[topic] = message;
|
||||||
|
if (topic == "weatherStation/windDeg") {
|
||||||
|
// etwas warten, bis die uebrigen Werte eingetroffen sind
|
||||||
|
setTimeout(function () { updateWeatherCards(name => mqttData["weatherStation/" + name]) }, 200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
client.on("error", function (error) {
|
||||||
|
console.log("MQTT: " + error.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('readystatechange', function () {
|
||||||
|
if (event.target.readyState === "complete") {
|
||||||
|
weatherMQTT.getMQTT();
|
||||||
|
mountMeteogram();
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<!-- Chart.js samt Zubehör - nur auf Seiten mit Diagrammen. -->
|
||||||
|
<script src="js/chart.min.js"></script>
|
||||||
|
<script src="js/chartjs-plugin-annotation.min.js"></script>
|
||||||
|
<script src="js/luxon.min.js"></script>
|
||||||
|
<script src="js/hammer.js"></script>
|
||||||
|
<script src="js/chartjs-scale-timestack.min.js"></script>
|
||||||
|
<script src="js/siprefix.min.js"></script>
|
||||||
|
<script>
|
||||||
|
Chart.register('chartjs-plugin-annotation');
|
||||||
|
|
||||||
|
const arraySum = (arr) => {
|
||||||
|
return arr.reduce((total, current) => {
|
||||||
|
return total + parseFloat(current);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tooltipLabel(context) {
|
||||||
|
let label = context.dataset.label || '';
|
||||||
|
if (label) {
|
||||||
|
label += ': ';
|
||||||
|
}
|
||||||
|
if (context.dataset.yAxisID == "y1") {
|
||||||
|
label += Math.round(context.parsed.y * 10) / 10 + " " + "%";
|
||||||
|
} else {
|
||||||
|
if (context.parsed.y !== null) {
|
||||||
|
ret = scale(Math.round(context.parsed.y), false);
|
||||||
|
label += ret[0] + " " + ret[1] + "W";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
};
|
||||||
|
|
||||||
|
function tooltipFooter(tooltipItems) {
|
||||||
|
let sum = 0;
|
||||||
|
tooltipItems.forEach(function (tooltipItem) {
|
||||||
|
if (tooltipItem.dataset.yAxisID != "y1") {
|
||||||
|
sum += tooltipItem.parsed.y;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ret = scale(Math.round(sum), false);
|
||||||
|
sum = ret[0] + " " + ret[1] + "W";
|
||||||
|
return 'Sum: ' + sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zeichenpuffer eines Canvas belegt Breite x Hoehe x DPR^2 x 4 Byte - auf
|
||||||
|
// hochaufloesenden Schirmen ist das der groesste Speicherposten der Seite.
|
||||||
|
// Deckel bei 1.5 kostet kaum Schaerfe und spart bei DPR 2 rund 44 %,
|
||||||
|
// bei DPR 3 rund 75 %.
|
||||||
|
Chart.defaults.devicePixelRatio = Math.min(1.5, window.devicePixelRatio || 1);
|
||||||
|
|
||||||
|
Chart.defaults.font.size = 10;
|
||||||
|
Chart.defaults.animations = false;
|
||||||
|
Chart.defaults.animation = false;
|
||||||
|
Chart.defaults.plugins.legend.position = "bottom";
|
||||||
|
Chart.defaults.plugins.legend.labels.pointStyleWidth = 10;
|
||||||
|
Chart.defaults.plugins.legend.labels.usePointStyle = true;
|
||||||
|
Chart.defaults.plugins.legend.labels.pointStyle = "line";
|
||||||
|
Chart.defaults.plugins.tooltip.position = "nearest";
|
||||||
|
Chart.defaults.plugins.tooltip.pointStyle = "circle";
|
||||||
|
Chart.defaults.plugins.tooltip.usePointStyle = true;
|
||||||
|
Chart.defaults.plugins.tooltip.boxWidth = 4;
|
||||||
|
Chart.defaults.plugins.tooltip.callbacks.footer = tooltipFooter;
|
||||||
|
Chart.defaults.plugins.tooltip.callbacks.label = tooltipLabel;
|
||||||
|
</script>
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
<!--begin::Footer-->
|
|
||||||
<footer class="app-footer">
|
|
||||||
<!--begin::To the end-->
|
|
||||||
<div class="float-end d-none d-sm-inline">Free simple code</div>
|
|
||||||
<!--end::To the end-->
|
|
||||||
<!--begin::Copyright-->
|
|
||||||
<strong>
|
|
||||||
No © 2025 by
|
|
||||||
<a href="https://el-wa.org" class="text-decoration-none">m0</a>
|
|
||||||
</strong>
|
|
||||||
All rights don't care.
|
|
||||||
<!--end::Copyright-->
|
|
||||||
</footer>
|
|
||||||
<!--end::Footer-->
|
|
||||||
<div class="modal fade" id="modalEV" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1">
|
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h4 class="modal-title" id="modal-title">Charger settings:</h4>
|
|
||||||
<div class="card-tools" style="position: absolute; right: 10px;">
|
|
||||||
<button type="button" class="btn btn-tool" data-bs-dismiss="modal">
|
|
||||||
<i class="bi bi-x-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body p-0 m-0 shadow" id="modal-body">
|
|
||||||
Loading...
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer justify-content-between">
|
|
||||||
<button type="button" class="btn btn-default" data-bs-dismiss="modal">Close</button>
|
|
||||||
<button type="button" id="modalSaveBtn" class="btn btn-primary">Save changes</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="offcanvas offcanvas-top" tabindex="-1" id="offcanvas" data-bs-backdrop="static">
|
|
||||||
<div class="offcanvas-header">
|
|
||||||
<h5 class="offcanvas-title" id="offcanvas-title">Offcanvas with backdrop</h5>
|
|
||||||
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="offcanvas-body" id="offcanvas-body">
|
|
||||||
<p>.....</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!--end::App Wrapper-->
|
|
||||||
<!--begin::Script-->
|
|
||||||
<!--begin::Third Party Plugin(OverlayScrollbars)
|
|
||||||
<script src="js/overlayscrollbars.browser.es6.min.js" crossorigin="anonymous"></script>-->
|
|
||||||
<!--end::Third Party Plugin(OverlayScrollbars)--><!--begin::Required Plugin(popperjs for Bootstrap 5)-->
|
|
||||||
<script src="js/meteogram.js"></script>
|
|
||||||
<script src='js/mqtt.js'></script>
|
|
||||||
<script src="js/popper.min.js" crossorigin="anonymous"></script>
|
|
||||||
<!--end::Required Plugin(popperjs for Bootstrap 5)--><!--begin::Required Plugin(Bootstrap 5)-->
|
|
||||||
<script src="js/bootstrap.min.js" crossorigin="anonymous"></script>
|
|
||||||
<!--end::Required Plugin(Bootstrap 5)--><!--begin::Required Plugin(AdminLTE)-->
|
|
||||||
<script src="js/adminlte.js"></script>
|
|
||||||
<!--end::Required Plugin(AdminLTE)--><!--begin::OverlayScrollbars Configure-->
|
|
||||||
<script src="js/modal-dynamic.min.js"></script>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- OPTIONAL SCRIPTS -->
|
|
||||||
|
|
||||||
<!-- sortablejs
|
|
||||||
<script src="js/Sortable.min.js"></script>
|
|
||||||
-->
|
|
||||||
<!-- sortablejs
|
|
||||||
<script>
|
|
||||||
if (document.querySelector('.connectedSortable')) {
|
|
||||||
new Sortable(document.querySelector('.connectedSortable'), {
|
|
||||||
group: 'shared',
|
|
||||||
handle: '.card-header',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const cardHeaders = document.querySelectorAll('.connectedSortable .card-header');
|
|
||||||
cardHeaders.forEach((cardHeader) => {
|
|
||||||
cardHeader.style.cursor = 'move';
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- ChartJS -->
|
|
||||||
<script src="js/chart.min.js"></script>
|
|
||||||
<script src="js/chartjs-plugin-annotation.min.js"></script>
|
|
||||||
<script src="js/luxon.min.js"></script>
|
|
||||||
<script src="js/hammer.js"></script>
|
|
||||||
<script src="js/chartjs-scale-timestack.min.js"></script>
|
|
||||||
<script src="js/siprefix.min.js"></script>
|
|
||||||
<script>
|
|
||||||
Chart.register('chartjs-plugin-annotation');
|
|
||||||
const arraySum = (arr) => {
|
|
||||||
return arr.reduce((total, current) => {
|
|
||||||
return total + parseFloat(current);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function tooltipLabel (context) {
|
|
||||||
let label = context.dataset.label || '';
|
|
||||||
if (label) {
|
|
||||||
label += ': ';
|
|
||||||
}
|
|
||||||
if (context.dataset.yAxisID == "y1") {
|
|
||||||
label += Math.round(context.parsed.y * 10) / 10 + " " + "%";
|
|
||||||
} else {
|
|
||||||
if (context.parsed.y !== null) {
|
|
||||||
ret = scale(Math.round(context.parsed.y), false);
|
|
||||||
label += ret[0] + " " + ret[1] + "W";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return label;
|
|
||||||
};
|
|
||||||
|
|
||||||
function tooltipFooter (tooltipItems){
|
|
||||||
let sum = 0;
|
|
||||||
|
|
||||||
tooltipItems.forEach(function(tooltipItem) {
|
|
||||||
if (tooltipItem.dataset.yAxisID == "y1") {
|
|
||||||
//sum2 += tooltipItem.parsed.y;
|
|
||||||
}else{
|
|
||||||
sum += tooltipItem.parsed.y;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//sum2 = Math.round(sum * 10) / 10 + " " + "%";
|
|
||||||
ret = scale(Math.round(sum), false);
|
|
||||||
sum = ret[0] + " " + ret[1] + "W";
|
|
||||||
return 'Sum: ' + sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
Chart.defaults.font.size = 10;
|
|
||||||
Chart.defaults.animations = false;
|
|
||||||
Chart.defaults.animation = false;
|
|
||||||
Chart.defaults.plugins.legend.position = "bottom";
|
|
||||||
Chart.defaults.plugins.legend.labels.pointStyleWidth = 10;
|
|
||||||
Chart.defaults.plugins.legend.labels.usePointStyle = true;
|
|
||||||
Chart.defaults.plugins.legend.labels.pointStyle = "line";
|
|
||||||
Chart.defaults.plugins.tooltip.position = "nearest";
|
|
||||||
Chart.defaults.plugins.tooltip.pointStyle = "circle";
|
|
||||||
Chart.defaults.plugins.tooltip.usePointStyle= true;
|
|
||||||
Chart.defaults.plugins.tooltip.boxWidth= 4;
|
|
||||||
Chart.defaults.plugins.tooltip.callbacks.footer = tooltipFooter;
|
|
||||||
Chart.defaults.plugins.tooltip.callbacks.label = tooltipLabel;
|
|
||||||
|
|
||||||
/*
|
|
||||||
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 + " " + "%";
|
|
||||||
} else {
|
|
||||||
if (context.parsed.y !== null) {
|
|
||||||
ret = scale(Math.round(context.parsed.y), false);
|
|
||||||
label += ret[0] + " " + ret[1] + "W";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return label;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},*/
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
<!--end::Body-->
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<!--begin::Footer-->
|
||||||
|
<footer class="app-footer">
|
||||||
|
<!--begin::To the end-->
|
||||||
|
<div class="float-end d-none d-sm-inline">Free simple code</div>
|
||||||
|
<!--end::To the end-->
|
||||||
|
<!--begin::Copyright-->
|
||||||
|
<strong>
|
||||||
|
No © 2025 by
|
||||||
|
<a href="https://el-wa.org" class="text-decoration-none">m0</a>
|
||||||
|
</strong>
|
||||||
|
All rights don't care.
|
||||||
|
<!--end::Copyright-->
|
||||||
|
</footer>
|
||||||
|
<!--end::Footer-->
|
||||||
|
<div class="modal fade" id="modalEV" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="modal-title">Charger settings:</h4>
|
||||||
|
<div class="card-tools" style="position: absolute; right: 10px;">
|
||||||
|
<button type="button" class="btn btn-tool" data-bs-dismiss="modal">
|
||||||
|
<i class="bi bi-x-lg"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body p-0 m-0 shadow" id="modal-body">
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer justify-content-between">
|
||||||
|
<button type="button" class="btn btn-default" data-bs-dismiss="modal">Close</button>
|
||||||
|
<button type="button" id="modalSaveBtn" class="btn btn-primary">Save changes</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="offcanvas offcanvas-top" tabindex="-1" id="offcanvas" data-bs-backdrop="static">
|
||||||
|
<div class="offcanvas-header">
|
||||||
|
<h5 class="offcanvas-title" id="offcanvas-title">Offcanvas with backdrop</h5>
|
||||||
|
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="offcanvas-body" id="offcanvas-body">
|
||||||
|
<p>.....</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!--end::App Wrapper-->
|
||||||
|
|
||||||
|
<!--begin::Script-->
|
||||||
|
<script src="js/popper.min.js" crossorigin="anonymous"></script>
|
||||||
|
<script src="js/bootstrap.min.js" crossorigin="anonymous"></script>
|
||||||
|
<script src="js/adminlte.min.js"></script>
|
||||||
|
<script src="js/modal-dynamic.min.js"></script>
|
||||||
|
<?php if ($page["mqtt"]): ?>
|
||||||
|
<!-- MQTT.js 5.14.1, dist/mqtt.min.js aus dem npm-Paket (368 KB statt 859 KB unminifiziert) -->
|
||||||
|
<script src="js/mqtt.min.js"></script>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($page["meteogram"]): ?>
|
||||||
|
<script src="js/meteogram.js"></script>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($page["charts"]): ?>
|
||||||
|
<?php include __DIR__ . "/charts.html"; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
<script src="js/solar/common.js?v=<?= filemtime("js/solar/common.js") ?>"></script>
|
||||||
|
<?php foreach ($page["scripts"] as $script): ?>
|
||||||
|
<script src="<?= $script ?>?v=<?= filemtime($script) ?>"></script>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<!--end::Script-->
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<!--end::Body-->
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -2,10 +2,9 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<!--begin::Head-->
|
<!--begin::Head-->
|
||||||
<?php
|
<?php
|
||||||
if(!isset($_GET["action"]))
|
// $_GET["action"] ist von index.php bereits auf eine gueltige Seite gesetzt.
|
||||||
$_GET["action"] = "solar";
|
if (!isset($_GET["floor"]))
|
||||||
if(!isset($_GET["floor"]))
|
|
||||||
$_GET["floor"] = "OG";
|
$_GET["floor"] = "OG";
|
||||||
?>
|
?>
|
||||||
<head>
|
<head>
|
||||||
@@ -29,24 +28,20 @@ if(!isset($_GET["floor"]))
|
|||||||
<!--begin::Accessibility Features-->
|
<!--begin::Accessibility Features-->
|
||||||
<!-- Skip links will be dynamically added by accessibility.js -->
|
<!-- Skip links will be dynamically added by accessibility.js -->
|
||||||
<meta name="supported-color-schemes" content="light dark" />
|
<meta name="supported-color-schemes" content="light dark" />
|
||||||
<link rel="preload" href="./css/adminlte.css?v=2" as="style" />
|
<link rel="preload" href="./css/adminlte.min.css?v=2" as="style" />
|
||||||
<link rel="stylesheet" href="./css/solar.css" as="style" />
|
<link rel="stylesheet" href="./css/solar.css" />
|
||||||
<!--end::Accessibility Features-->
|
<!--end::Accessibility Features-->
|
||||||
|
|
||||||
<!--begin::Fonts-->
|
<!--begin::Fonts-->
|
||||||
<link rel="stylesheet" href="assets/fonts/font_poppins.css" media="print" onload="this.media='all'" />
|
<link rel="stylesheet" href="assets/fonts/font_poppins.css" media="print" onload="this.media='all'" />
|
||||||
<!--end::Fonts-->
|
<!--end::Fonts-->
|
||||||
|
|
||||||
<!--begin::Third Party Plugin(OverlayScrollbars)
|
|
||||||
<link rel="stylesheet" href="css/overlayscrollbars.min.css" />-->
|
|
||||||
<!--end::Third Party Plugin(OverlayScrollbars)-->
|
|
||||||
|
|
||||||
<!--begin::Third Party Plugin(Bootstrap Icons)-->
|
<!--begin::Third Party Plugin(Bootstrap Icons)-->
|
||||||
<link rel="stylesheet" href="css/bootstrap-icons.min.css" />
|
<link rel="stylesheet" href="css/bootstrap-icons.min.css" />
|
||||||
<!--end::Third Party Plugin(Bootstrap Icons)-->
|
<!--end::Third Party Plugin(Bootstrap Icons)-->
|
||||||
|
|
||||||
<!--begin::Required Plugin(AdminLTE)-->
|
<!--begin::Required Plugin(AdminLTE)-->
|
||||||
<link rel="stylesheet" href="./css/adminlte.css?v=2" />
|
<link rel="stylesheet" href="./css/adminlte.min.css?v=2" />
|
||||||
<!--end::Required Plugin(AdminLTE)-->
|
<!--end::Required Plugin(AdminLTE)-->
|
||||||
|
|
||||||
|
|
||||||
@@ -124,7 +119,7 @@ if(!isset($_GET["floor"]))
|
|||||||
</a>
|
</a>
|
||||||
<ul class="nav nav-treeview ps-4">
|
<ul class="nav nav-treeview ps-4">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="?action=solar" class="nav-link<?php if($_GET["action"]=="solar" || $_GET["action"]==""){echo " active";} ?>">
|
<a href="?action=solar" class="nav-link<?php if($_GET["action"]=="solar"){echo " active";} ?>">
|
||||||
<i class="nav-icon bi bi-brightness-alt-high"></i>
|
<i class="nav-icon bi bi-brightness-alt-high"></i>
|
||||||
<p>Solar</p>
|
<p>Solar</p>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,163 +1,104 @@
|
|||||||
<!--begin::App Main-->
|
<!--begin::App Main-->
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<!--begin::App Content Header-->
|
<!--begin::App Content Header-->
|
||||||
<div class="app-content-header">
|
<div class="app-content-header">
|
||||||
<!--begin::Container-->
|
<!--begin::Container-->
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!--begin::Row-->
|
<!--begin::Row-->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<h3 class="mb-0">Heizung</h3>
|
<h3 class="mb-0">Heizung</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--end::Row-->
|
<!--end::Row-->
|
||||||
</div>
|
</div>
|
||||||
<!--end::Container-->
|
<!--end::Container-->
|
||||||
</div>
|
</div>
|
||||||
<!--end::App Content Header-->
|
<!--end::App Content Header-->
|
||||||
<!--begin::App Content-->
|
<!--begin::App Content-->
|
||||||
<div class="app-content">
|
<div class="app-content">
|
||||||
<!--begin::Container-->
|
<!--begin::Container-->
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!--begin::Row-->
|
<!--begin::Row-->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- Start col -->
|
<!-- Start col -->
|
||||||
|
|
||||||
<div class="col-xxl-3 col-xl-4 col-lg-5 col-md-5 d-flex align-items-stretch">
|
<div class="col-xxl-3 col-xl-4 col-lg-5 col-md-5 d-flex align-items-stretch">
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
<div class="card p-0 mb-4" style="width:100%">
|
||||||
<div class="card-header pb-0 pt-1">
|
<div class="card-header pb-0 pt-1">
|
||||||
<h3 class="card-title">Heater</h3>
|
<h3 class="card-title">Heater</h3>
|
||||||
<div class="card-tools">
|
<div class="card-tools">
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
<i class="bi bi-x-lg"></i>
|
<i class="bi bi-x-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-3 d-flex flex-column">
|
<div class="card-body p-3 d-flex flex-column">
|
||||||
<object data="assets/img/heater.svg"></object>
|
<object data="assets/img/heater.svg"></object>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card -->
|
<!-- /.card -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Heater Graph-->
|
<!-- Heater Graph-->
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="card mb-4 p-0">
|
<div class="card mb-4 p-0">
|
||||||
<div class="card-header pb-0 pt-1">
|
<div class="card-header pb-0 pt-1">
|
||||||
<h3 class="card-title">Temperaturen</h3>
|
<h3 class="card-title">Temperaturen</h3>
|
||||||
<div class="card-tools">
|
<div class="card-tools">
|
||||||
<button type="button" class="btn btn-tool" title="Zoom out">
|
<button type="button" class="btn btn-tool" title="Zoom out">
|
||||||
<i class="bi bi-zoom-out"></i>
|
<i class="bi bi-zoom-out"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-tool" title="Zoom in">
|
<button type="button" class="btn btn-tool" title="Zoom in">
|
||||||
<i class="bi bi-zoom-in"></i>
|
<i class="bi bi-zoom-in"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
<i class="bi bi-x-lg"></i>
|
<i class="bi bi-x-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body pb-1">
|
<div class="card-body pb-1">
|
||||||
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
||||||
<canvas id="heat-chart" height="400px;"></canvas>
|
<canvas id="heat-chart" height="400px;"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card -->
|
<!-- /.card -->
|
||||||
<!-- Water Graph-->
|
<!-- Water Graph-->
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="card mb-4 p-0">
|
<div class="card mb-4 p-0">
|
||||||
<div class="card-header pb-0 pt-1">
|
<div class="card-header pb-0 pt-1">
|
||||||
<h3 class="card-title">Wasserverbrauch</h3>
|
<h3 class="card-title">Wasserverbrauch</h3>
|
||||||
<div class="card-tools">
|
<div class="card-tools">
|
||||||
<button type="button" class="btn btn-tool" title="Zoom out">
|
<button type="button" class="btn btn-tool" title="Zoom out">
|
||||||
<i class="bi bi-zoom-out"></i>
|
<i class="bi bi-zoom-out"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-tool" title="Zoom in">
|
<button type="button" class="btn btn-tool" title="Zoom in">
|
||||||
<i class="bi bi-zoom-in"></i>
|
<i class="bi bi-zoom-in"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
<i class="bi bi-x-lg"></i>
|
<i class="bi bi-x-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body pb-1">
|
<div class="card-body pb-1">
|
||||||
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
||||||
<canvas id="water-chart" height="400px;"></canvas>
|
<canvas id="water-chart" height="400px;"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card -->
|
<!-- /.card -->
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<?php include __DIR__ . "/weather_cards.html"; ?>
|
||||||
<!-- Start col -->
|
<!-- /.row (main row) -->
|
||||||
<div class="m-0 col-xl-2 col-4 d-flex">
|
</div>
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
<!--end::Container-->
|
||||||
<div class="card-header pb-0 pt-1">
|
</div>
|
||||||
<h3 class="card-title">Temp.</h3>
|
<!--end::App Content-->
|
||||||
</div>
|
</main>
|
||||||
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
|
||||||
<h3 id="temp">--</h3>°C
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="m-0 col-xl-2 col-4 d-flex">
|
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Feuchte</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
|
||||||
<h3 id="humidity">--</h3>%rF
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="m-0 col-xl-2 col-4 d-flex">
|
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Wind</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
|
||||||
<div id="windDir" class="winddir" style="transform: rotate(180deg);"></div>
|
|
||||||
<h3 id="windSpd">--</h3>km/h
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="m-0 col-xl-2 col-4 d-flex">
|
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Böen</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
|
||||||
<div id="windDirGust" class="winddir" style="transform: rotate(180deg);"></div>
|
|
||||||
<h3 id="windGust">--</h3>km/h
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="m-0 col-xl-2 col-4 d-flex">
|
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Druck</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
|
||||||
<h3 id="ambPress">--</h3>hPa
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- /.row (main row) -->
|
|
||||||
</div>
|
|
||||||
<!--end::Container-->
|
|
||||||
</div>
|
|
||||||
<!--end::App Content-->
|
|
||||||
</main>
|
|
||||||
<!--end::App Main-->
|
<!--end::App Main-->
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
<!--begin::App Main-->
|
|
||||||
<main class="app-main">
|
|
||||||
<!--begin::App Content Header-->
|
|
||||||
<div class="app-content-header">
|
|
||||||
<!--begin::Container-->
|
|
||||||
<div class="container-fluid">
|
|
||||||
<!--begin::Row-->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<h3 class="mb-0">Vergangenheit</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!--end::Row-->
|
|
||||||
</div>
|
|
||||||
<!--end::Container-->
|
|
||||||
</div>
|
|
||||||
<!--end::App Content Header-->
|
|
||||||
<!--begin::App Content-->
|
|
||||||
<div class="app-content">
|
|
||||||
<!--begin::Container-->
|
|
||||||
<div class="container-fluid">
|
|
||||||
<!--begin::Row-->
|
|
||||||
<div class="row row-info">
|
|
||||||
<!-- Start col -->
|
|
||||||
<!-- Consumption Graph-->
|
|
||||||
<div class="col-xl-6 col-m-12">
|
|
||||||
<div class="card mb-4 p-0">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Power consumption</h3>
|
|
||||||
<div class="card-tools">
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom out">
|
|
||||||
<i class="bi bi-zoom-out"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom in">
|
|
||||||
<i class="bi bi-zoom-in"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
|
||||||
<i class="bi bi-x-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-body pb-1">
|
|
||||||
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
|
||||||
<canvas id="consumption-chart" height="400px;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Production Graph -->
|
|
||||||
<div class="col-xl-6 col-m-12">
|
|
||||||
<div class="card mb-4 p-0">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Power production</h3>
|
|
||||||
<div class="card-tools">
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom out">
|
|
||||||
<i class="bi bi-zoom-out"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom in">
|
|
||||||
<i class="bi bi-zoom-in"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
|
||||||
<i class="bi bi-x-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-body pb-1">
|
|
||||||
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
|
||||||
<canvas id="production-chart" height="400px;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.card -->
|
|
||||||
</div>
|
|
||||||
<!-- /.Start col -->
|
|
||||||
</div>
|
|
||||||
<div class="row row-info">
|
|
||||||
<!-- Start col -->
|
|
||||||
<!-- Consumption Graph-->
|
|
||||||
<div class="col-xl-6 col-m-12">
|
|
||||||
<div class="card mb-4 p-0">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Power consumption</h3>
|
|
||||||
<div class="card-tools">
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom out">
|
|
||||||
<i class="bi bi-zoom-out"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom in">
|
|
||||||
<i class="bi bi-zoom-in"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
|
||||||
<i class="bi bi-x-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-body pb-1">
|
|
||||||
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
|
||||||
<canvas id="consumption-chart-year" height="400px;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Production Graph -->
|
|
||||||
<div class="col-xl-6 col-m-12">
|
|
||||||
<div class="card mb-4 p-0">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Power production</h3>
|
|
||||||
<div class="card-tools">
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom out">
|
|
||||||
<i class="bi bi-zoom-out"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom in">
|
|
||||||
<i class="bi bi-zoom-in"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
|
||||||
<i class="bi bi-x-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-body pb-1">
|
|
||||||
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
|
||||||
<canvas id="production-chart-year" height="400px;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.card -->
|
|
||||||
</div>
|
|
||||||
<!-- /.Start col -->
|
|
||||||
</div>
|
|
||||||
<div class="row row-info">
|
|
||||||
<!-- Start col -->
|
|
||||||
<!-- Consumption Graph-->
|
|
||||||
<div class="col-xl-6 col-m-12">
|
|
||||||
<div class="card mb-4 p-0">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Power consumption</h3>
|
|
||||||
<div class="card-tools">
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom out">
|
|
||||||
<i class="bi bi-zoom-out"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom in">
|
|
||||||
<i class="bi bi-zoom-in"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
|
||||||
<i class="bi bi-x-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-body pb-1">
|
|
||||||
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
|
||||||
<canvas id="consumption-chart-decade" height="400px;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Production Graph -->
|
|
||||||
<div class="col-xl-6 col-m-12">
|
|
||||||
<div class="card mb-4 p-0">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Power production</h3>
|
|
||||||
<div class="card-tools">
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom out">
|
|
||||||
<i class="bi bi-zoom-out"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" title="Zoom in">
|
|
||||||
<i class="bi bi-zoom-in"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
|
||||||
<i class="bi bi-x-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-body pb-1">
|
|
||||||
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
|
||||||
<canvas id="production-chart-decade" height="400px;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.card -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- /.Start col -->
|
|
||||||
</div>
|
|
||||||
<div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 d-flex align-items-stretch">
|
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Statistik dieses Jahr</h3>
|
|
||||||
<div class="card-tools">
|
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
|
||||||
<i class="bi bi-x-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row-cols-1 row-cols-md-1 g-4 p-2 pb-0" id="Stats-Year">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.card -->
|
|
||||||
</div>
|
|
||||||
<div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 d-flex align-items-stretch">
|
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Statistik letztes Jahr</h3>
|
|
||||||
<div class="card-tools">
|
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
|
||||||
<i class="bi bi-x-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row-cols-1 row-cols-md-1 g-4 p-2 pb-0" id="Stats-Lastyear">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.card -->
|
|
||||||
</div>
|
|
||||||
<div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 d-flex align-items-stretch">
|
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Statistik vorletztes Jahr</h3>
|
|
||||||
<div class="card-tools">
|
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
|
||||||
<i class="bi bi-x-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row-cols-1 row-cols-md-1 g-4 p-2 pb-0" id="Stats-Prelastyear">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.card -->
|
|
||||||
</div>
|
|
||||||
<!-- /.row (main row) -->
|
|
||||||
</div>
|
|
||||||
<!--end::Container-->
|
|
||||||
</div>
|
|
||||||
<!--end::App Content-->
|
|
||||||
</main>
|
|
||||||
<!--end::App Main-->
|
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
// Die sechs Diagramme unterscheiden sich nur in Zeitraum und Canvas-ID.
|
||||||
|
$periods = [
|
||||||
|
"month" => "Letzter Monat",
|
||||||
|
"year" => "Letzte 13 Monate",
|
||||||
|
"decade" => "Letzte 10 Jahre",
|
||||||
|
];
|
||||||
|
// Die Jahresstatistiken darunter folgen demselben Muster.
|
||||||
|
$statistics = [
|
||||||
|
"Stats-Year" => "Statistik dieses Jahr",
|
||||||
|
"Stats-Lastyear" => "Statistik letztes Jahr",
|
||||||
|
"Stats-Prelastyear" => "Statistik vorletztes Jahr",
|
||||||
|
];
|
||||||
|
?>
|
||||||
|
<!--begin::App Main-->
|
||||||
|
<main class="app-main">
|
||||||
|
<!--begin::App Content Header-->
|
||||||
|
<div class="app-content-header">
|
||||||
|
<!--begin::Container-->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<!--begin::Row-->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<h3 class="mb-0">Vergangenheit</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--end::Row-->
|
||||||
|
</div>
|
||||||
|
<!--end::Container-->
|
||||||
|
</div>
|
||||||
|
<!--end::App Content Header-->
|
||||||
|
<!--begin::App Content-->
|
||||||
|
<div class="app-content">
|
||||||
|
<!--begin::Container-->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<?php foreach ($periods as $period => $periodTitle): ?>
|
||||||
|
<div class="row row-info">
|
||||||
|
<?php foreach (["consumption" => "Power consumption", "production" => "Power production"] as $kind => $kindTitle): ?>
|
||||||
|
<div class="col-xl-6 col-m-12">
|
||||||
|
<div class="card mb-4 p-0">
|
||||||
|
<div class="card-header pb-0 pt-1">
|
||||||
|
<h3 class="card-title"><?= $kindTitle ?> – <?= $periodTitle ?></h3>
|
||||||
|
<div class="card-tools">
|
||||||
|
<button type="button" class="btn btn-tool" title="Zoom out">
|
||||||
|
<i class="bi bi-zoom-out"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-tool" title="Zoom in">
|
||||||
|
<i class="bi bi-zoom-in"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
|
<i class="bi bi-x-lg"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body pb-1">
|
||||||
|
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
||||||
|
<canvas id="<?= $kind ?>-chart<?= $period == "month" ? "" : "-" . $period ?>" height="400px;"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php foreach ($statistics as $id => $title): ?>
|
||||||
|
<div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 d-flex align-items-stretch">
|
||||||
|
<div class="card p-0 mb-4" style="width:100%">
|
||||||
|
<div class="card-header pb-0 pt-1">
|
||||||
|
<h3 class="card-title"><?= $title ?></h3>
|
||||||
|
<div class="card-tools">
|
||||||
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
|
<i class="bi bi-x-lg"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row-cols-1 row-cols-md-1 g-4 p-2 pb-0" id="<?= $id ?>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.card -->
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<!-- /.row (main row) -->
|
||||||
|
</div>
|
||||||
|
<!--end::Container-->
|
||||||
|
</div>
|
||||||
|
<!--end::App Content-->
|
||||||
|
</main>
|
||||||
|
<!--end::App Main-->
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<?php require_once(__DIR__ . "/rooms.php"); ?>
|
||||||
<!--begin::App Main-->
|
<!--begin::App Main-->
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<!--begin::App Content Header-->
|
<!--begin::App Content Header-->
|
||||||
@@ -104,142 +105,22 @@
|
|||||||
<use href="#floorBtn" stroke="#aa7713" />
|
<use href="#floorBtn" stroke="#aa7713" />
|
||||||
<text fill="#aa7713" style="font: 3em sans-serif;" transform="translate(63,90)">UG</text>
|
<text fill="#aa7713" style="font: 3em sans-serif;" transform="translate(63,90)">UG</text>
|
||||||
</g>
|
</g>
|
||||||
<g id="OG_Info" <?php if($_GET["floor"] != "OG"){echo "display='none'";} ?> >
|
<?php foreach ($floors as $floor): ?>
|
||||||
<g transform="translate(180,140)" onclick="openHeaterSettings('OG_Wohnzimmer');" cursor="pointer">
|
<g id="<?= $floor ?>_Info" <?php if ($floor != "OG") echo 'opacity="0" '; ?><?php if($_GET["floor"] != $floor){echo "display='none'";} ?> >
|
||||||
|
<?php foreach (roomsOnFloor($floor) as $room): ?>
|
||||||
|
<g transform="translate(<?= $room["x"] ?>,<?= $room["y"] ?>)" onclick="openHeaterSettings('<?= $floor ?>_<?= $room["mqtt"] ?>');" cursor="pointer">
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
<rect width="24" height="19" rx="5" fill="#0006" />
|
||||||
<use id="OG_wozi_heater" href="#heater" display="none" />
|
<use id="<?= $floor ?>_<?= $room["id"] ?>_heater" href="#heater" display="none" />
|
||||||
<use id="OG_wozi_buffer" href="#buffer" display="none" />
|
<use id="<?= $floor ?>_<?= $room["id"] ?>_buffer" href="#buffer" display="none" />
|
||||||
<text fill="#fff" style="font: 4px sans-serif;" cursor="pointer">
|
|
||||||
<tspan id="OG_pres_wozi" y="5" x="12" text-anchor="middle" cursor="pointer">---- hPa</tspan>
|
|
||||||
<tspan id="OG_tmp_wozi" x="12" dy="1em" font-size="1.6em" text-anchor="middle" cursor="pointer">--,- °C</tspan>
|
|
||||||
<tspan id="OG_hum_wozi" x="12" dy="1.2em" text-anchor="middle" cursor="pointer">-- %rF</tspan>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(130,80)" onclick="openHeaterSettings('OG_KiZi');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="OG_kizi_heater" href="#heater" display="none" />
|
|
||||||
<use id="OG_kizi_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
<text fill="#fff" style="font: 4px sans-serif;">
|
||||||
<tspan id="OG_pres_kizi" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
<tspan id="<?= $floor ?>_pres_<?= $room["id"] ?>" y="5" x="12" text-anchor="middle">---- hPa</tspan>
|
||||||
<tspan id="OG_tmp_kizi" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
<tspan id="<?= $floor ?>_tmp_<?= $room["id"] ?>" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
||||||
<tspan id="OG_hum_kizi" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
<tspan id="<?= $floor ?>_hum_<?= $room["id"] ?>" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(235,70)" onclick="openHeaterSettings('OG_Schlafzimmer');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="OG_schlafen_heater" href="#heater" display="none" />
|
|
||||||
<use id="OG_schlafen_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
|
||||||
<tspan id="OG_pres_schlafen" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
|
||||||
<tspan id="OG_tmp_schlafen" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
|
||||||
<tspan id="OG_hum_schlafen" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(260,120)" onclick="openHeaterSettings('OG_Bad');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="OG_bad_heater" href="#heater" display="none" />
|
|
||||||
<use id="OG_bad_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
|
||||||
<tspan id="OG_pres_bad" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
|
||||||
<tspan id="OG_tmp_bad" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
|
||||||
<tspan id="OG_hum_bad" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(265,175)" onclick="openHeaterSettings('OG_Buero');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="OG_buero_heater" href="#heater" display="none" />
|
|
||||||
<use id="OG_buero_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
|
||||||
<tspan id="OG_pres_buero" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
|
||||||
<tspan id="OG_tmp_buero" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
|
||||||
<tspan id="OG_hum_buero" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g id="EG_Info" opacity="0" <?php if($_GET["floor"] != "EG"){echo "display='none'";} ?> >
|
|
||||||
<g transform="translate(185,150)" onclick="openHeaterSettings('EG_Wohnzimmer');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="EG_wozi_heater" href="#heater" display="none" />
|
|
||||||
<use id="EG_wozi_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
|
||||||
<tspan id="EG_pres_wozi" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
|
||||||
<tspan id="EG_tmp_wozi" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
|
||||||
<tspan id="EG_hum_wozi" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(130,90)" onclick="openHeaterSettings('EG_Florian');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="EG_kizi_heater" href="#heater" display="none" />
|
|
||||||
<use id="EG_kizi_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
|
||||||
<tspan id="EG_pres_kizi" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
|
||||||
<tspan id="EG_tmp_kizi" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
|
||||||
<tspan id="EG_hum_kizi" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(235,80)" onclick="openHeaterSettings('EG_Schlafen');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="EG_schlafen_heater" href="#heater" display="none" />
|
|
||||||
<use id="EG_schlafen_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
|
||||||
<tspan id="EG_pres_schlafen" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
|
||||||
<tspan id="EG_tmp_schlafen" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
|
||||||
<tspan id="EG_hum_schlafen" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(253,130)" onclick="openHeaterSettings('EG_Bad');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="EG_bad_heater" href="#heater" display="none" />
|
|
||||||
<use id="EG_bad_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
|
||||||
<tspan id="EG_pres_bad" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
|
||||||
<tspan id="EG_tmp_bad" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
|
||||||
<tspan id="EG_hum_bad" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(258,180)" onclick="openHeaterSettings('EG_Magdalena');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="EG_buero_heater" href="#heater" display="none" />
|
|
||||||
<use id="EG_buero_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
|
||||||
<tspan id="EG_pres_buero" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
|
||||||
<tspan id="EG_tmp_buero" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
|
||||||
<tspan id="EG_hum_buero" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g id="UG_Info" opacity="0" <?php if($_GET["floor"] != "UG"){echo "display='none'";} ?> >
|
|
||||||
<g transform="translate(140,140)" onclick="openHeaterSettings('UG_Buero');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="UG_buero_heater" href="#heater" display="none" />
|
|
||||||
<use id="UG_buero_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
|
||||||
<tspan id="UG_pres_buero" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
|
||||||
<tspan id="UG_tmp_buero" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
|
||||||
<tspan id="UG_hum_buero" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(210,80)" onclick="openHeaterSettings('UG_Bad');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="UG_bad_heater" href="#heater" display="none" />
|
|
||||||
<use id="UG_bad_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
|
||||||
<tspan id="UG_pres_bad" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
|
||||||
<tspan id="UG_tmp_bad" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
|
||||||
<tspan id="UG_hum_bad" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(190,195)" onclick="openHeaterSettings('UG_Kueche');" cursor="pointer">
|
|
||||||
<rect width="24" height="19" rx="5" fill="#0006" />
|
|
||||||
<use id="UG_kueche_heater" href="#heater" display="none" />
|
|
||||||
<use id="UG_kueche_buffer" href="#buffer" display="none" />
|
|
||||||
<text fill="#fff" style="font: 4px sans-serif;">
|
|
||||||
<tspan id="UG_pres_kueche" y="5" x="12" text-anchor="middle" >---- hPa</tspan>
|
|
||||||
<tspan id="UG_tmp_kueche" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
|
|
||||||
<tspan id="UG_hum_kueche" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
|
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
|
<?php endforeach; ?>
|
||||||
</g>
|
</g>
|
||||||
|
<?php endforeach; ?>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
@@ -327,21 +208,15 @@
|
|||||||
</main>
|
</main>
|
||||||
<!--end::App Main-->
|
<!--end::App Main-->
|
||||||
|
|
||||||
<?php
|
<script>
|
||||||
if(isset($_GET["floor"])){
|
// Raumtabelle aus restricted/rooms.php - homeMQTT.js aktualisiert darueber
|
||||||
echo "<script> document.addEventListener('readystatechange', function () {
|
// die SVG-Kacheln, ohne die Raeume noch einmal aufzufuehren.
|
||||||
if (event.target.readyState === 'complete') {";
|
const homeRooms = <?= json_encode($rooms) ?>;
|
||||||
switch($_GET["floor"]){
|
<?php if ($_GET["floor"] != "OG" && in_array($_GET["floor"], $floors)): ?>
|
||||||
case "EG":
|
document.addEventListener('readystatechange', function () {
|
||||||
echo "switchFloor('EG');";
|
if (event.target.readyState === 'complete') {
|
||||||
break;
|
switchFloor('<?= $_GET["floor"] ?>');
|
||||||
case "OG":
|
}
|
||||||
break;
|
});
|
||||||
case "UG":
|
<?php endif; ?>
|
||||||
echo "switchFloor('UG');";
|
</script>
|
||||||
break;
|
|
||||||
}
|
|
||||||
echo "}
|
|
||||||
});</script>";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Einzige Quelle für die Räume der Home-Ansicht.
|
||||||
|
*
|
||||||
|
* Aus dieser Tabelle entstehen sowohl die SVG-Kacheln in home.php als auch
|
||||||
|
* die Aktualisierungsschleife in js/solar/homeMQTT.js (die Tabelle wird dafür
|
||||||
|
* als JSON in die Seite geschrieben). Ein neuer oder umbenannter Raum ist
|
||||||
|
* damit eine Zeile hier statt drei Stellen im Code.
|
||||||
|
*
|
||||||
|
* floor Etage; bestimmt zugleich den Zweig Raumtemp/<floor>/
|
||||||
|
* mqtt Name des Raums im MQTT-Baum: Raumtemp/<floor>/<mqtt>/...
|
||||||
|
* id Kürzel in den SVG-Element-IDs: <floor>_tmp_<id>, <floor>_<id>_heater
|
||||||
|
* x, y Position der Kachel im SVG (viewBox 400x300)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Reihenfolge im Menü und in der Anzeige; OG ist die Standardetage.
|
||||||
|
$floors = ["OG", "EG", "UG"];
|
||||||
|
|
||||||
|
$rooms = [
|
||||||
|
["floor" => "OG", "mqtt" => "Wohnzimmer", "id" => "wozi", "x" => 180, "y" => 140],
|
||||||
|
["floor" => "OG", "mqtt" => "KiZi", "id" => "kizi", "x" => 130, "y" => 80],
|
||||||
|
["floor" => "OG", "mqtt" => "Schlafzimmer", "id" => "schlafen", "x" => 235, "y" => 70],
|
||||||
|
["floor" => "OG", "mqtt" => "Bad", "id" => "bad", "x" => 260, "y" => 120],
|
||||||
|
["floor" => "OG", "mqtt" => "Buero", "id" => "buero", "x" => 265, "y" => 175],
|
||||||
|
["floor" => "EG", "mqtt" => "Wohnzimmer", "id" => "wozi", "x" => 185, "y" => 150],
|
||||||
|
["floor" => "EG", "mqtt" => "Florian", "id" => "kizi", "x" => 130, "y" => 90],
|
||||||
|
["floor" => "EG", "mqtt" => "Schlafen", "id" => "schlafen", "x" => 235, "y" => 80],
|
||||||
|
["floor" => "EG", "mqtt" => "Bad", "id" => "bad", "x" => 253, "y" => 130],
|
||||||
|
["floor" => "EG", "mqtt" => "Magdalena", "id" => "buero", "x" => 258, "y" => 180],
|
||||||
|
["floor" => "UG", "mqtt" => "Buero", "id" => "buero", "x" => 140, "y" => 140],
|
||||||
|
["floor" => "UG", "mqtt" => "Bad", "id" => "bad", "x" => 210, "y" => 80],
|
||||||
|
["floor" => "UG", "mqtt" => "Kueche", "id" => "kueche", "x" => 190, "y" => 195],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Räume einer Etage, in der Reihenfolge der Tabelle. */
|
||||||
|
function roomsOnFloor($floor)
|
||||||
|
{
|
||||||
|
return array_values(array_filter($GLOBALS["rooms"], function ($room) use ($floor) {
|
||||||
|
return $room["floor"] == $floor;
|
||||||
|
}));
|
||||||
|
}
|
||||||
@@ -1,250 +1,191 @@
|
|||||||
<style>
|
<style>
|
||||||
.datepicker-native {
|
.datepicker-native {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.datepicker-native-input {
|
.datepicker-native-input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
.datepicker-native-input::-webkit-calendar-picker-indicator {
|
.datepicker-native-input::-webkit-calendar-picker-indicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!--begin::App Main-->
|
<!--begin::App Main-->
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<!--begin::App Content Header-->
|
<!--begin::App Content Header-->
|
||||||
<div class="app-content-header">
|
<div class="app-content-header">
|
||||||
<!--begin::Container-->
|
<!--begin::Container-->
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!--begin::Row-->
|
<!--begin::Row-->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<h3 class="mb-0">Solar</h3>
|
<h3 class="mb-0">Solar</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--end::Row-->
|
<!--end::Row-->
|
||||||
</div>
|
</div>
|
||||||
<!--end::Container-->
|
<!--end::Container-->
|
||||||
</div>
|
</div>
|
||||||
<!--end::App Content Header-->
|
<!--end::App Content Header-->
|
||||||
<!--begin::App Content-->
|
<!--begin::App Content-->
|
||||||
<div class="app-content">
|
<div class="app-content">
|
||||||
<!--begin::Container-->
|
<!--begin::Container-->
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!--begin::Row-->
|
<!--begin::Row-->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- Start col -->
|
<!-- Start col -->
|
||||||
<div class="col-xxl-12 col-xl-12 d-flex align-items-stretch">
|
<div class="col-xxl-12 col-xl-12 d-flex align-items-stretch">
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
<div class="card p-0 mb-4" style="width:100%">
|
||||||
<div class="card-header pb-0 pt-1">
|
<div class="card-header pb-0 pt-1">
|
||||||
<h3 class="card-title">Realtime</h3>
|
<h3 class="card-title">Realtime</h3>
|
||||||
<div class="card-tools">
|
<div class="card-tools">
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
<i class="bi bi-x-lg"></i>
|
<i class="bi bi-x-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-0 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;max-height:800px;">
|
<div class="card-body p-0 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;max-height:800px;">
|
||||||
%%INSERTSVG%%
|
<?php readfile(__DIR__ . "/../assets/img/realtime.svg"); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card -->
|
<!-- /.card -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 d-flex align-items-stretch">
|
<div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 d-flex align-items-stretch">
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
<div class="card p-0 mb-4" style="width:100%">
|
||||||
<div class="card-header pb-0 pt-1">
|
<div class="card-header pb-0 pt-1">
|
||||||
<h3 class="card-title">Statistik dieses Jahr</h3>
|
<h3 class="card-title">Statistik dieses Jahr</h3>
|
||||||
<div class="card-tools">
|
<div class="card-tools">
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
<i class="bi bi-x-lg"></i>
|
<i class="bi bi-x-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row-cols-1 row-cols-md-1 g-4 p-2 pb-0" id="Stats-Year">
|
<div class="row-cols-1 row-cols-md-1 g-4 p-2 pb-0" id="Stats-Year">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card -->
|
<!-- /.card -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 d-flex align-items-stretch">
|
<div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 d-flex align-items-stretch">
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
<div class="card p-0 mb-4" style="width:100%">
|
||||||
<div class="card-header pb-0 pt-1">
|
<div class="card-header pb-0 pt-1">
|
||||||
<h3 class="card-title">Forecast</h3>
|
<h3 class="card-title">Forecast</h3>
|
||||||
<div class="card-tools">
|
<div class="card-tools">
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
<i class="bi bi-x-lg"></i>
|
<i class="bi bi-x-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body pb-1" id="meteogram">
|
<div class="card-body pb-1" id="meteogram">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card -->
|
<!-- /.card -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Forecast Graph-->
|
<!-- Forecast Graph-->
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="card mb-4 p-0">
|
<div class="card mb-4 p-0">
|
||||||
<div class="card-header pb-0 pt-1">
|
<div class="card-header pb-0 pt-1">
|
||||||
<h3 class="card-title">Forecast</h3>
|
<h3 class="card-title">Forecast</h3>
|
||||||
<div class="card-tools">
|
<div class="card-tools">
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
<i class="bi bi-x-lg"></i>
|
<i class="bi bi-x-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body pb-1">
|
<div class="card-body pb-1">
|
||||||
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
||||||
<canvas id="forecast-chart" height="400px;"></canvas>
|
<canvas id="forecast-chart" height="400px;"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Consumption Graph-->
|
<!-- Consumption Graph-->
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="card mb-4 p-0">
|
<div class="card mb-4 p-0">
|
||||||
<div class="card-header pb-0 pt-1">
|
<div class="card-header pb-0 pt-1">
|
||||||
<h3 class="card-title">Power consumption</h3>
|
<h3 class="card-title">Power consumption</h3>
|
||||||
<div class="card-tools">
|
<div class="card-tools">
|
||||||
<button type="button" class="btn btn-tool" title="Voriger Tag" onclick="prevDay()">
|
<button type="button" class="btn btn-tool" title="Voriger Tag" onclick="prevDay()">
|
||||||
<i class="bi bi-skip-backward"></i>
|
<i class="bi bi-skip-backward"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" type="btn btn-tool" class="btn btn-tool datepicker-native">
|
<button type="button" type="btn btn-tool" class="btn btn-tool datepicker-native">
|
||||||
<i class="bi bi-calendar-week"></i>
|
<i class="bi bi-calendar-week"></i>
|
||||||
<input type="date" id="DatePickerCons" class="datepicker-native-input" onInput="changeDay(event);" />
|
<input type="date" id="DatePickerCons" class="datepicker-native-input" onInput="changeDay(event);" />
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-tool" title="Nächster Tag" onclick="nextDay()">
|
<button type="button" class="btn btn-tool" title="Nächster Tag" onclick="nextDay()">
|
||||||
<i class="bi bi-skip-forward"></i>
|
<i class="bi bi-skip-forward"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
<i class="bi bi-x-lg"></i>
|
<i class="bi bi-x-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body pb-1">
|
<div class="card-body pb-1">
|
||||||
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
||||||
<canvas id="consumption-chart" height="400px;"></canvas>
|
<canvas id="consumption-chart" height="400px;"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Production Graph -->
|
<!-- Production Graph -->
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="card mb-4 p-0">
|
<div class="card mb-4 p-0">
|
||||||
<div class="card-header pb-0 pt-1">
|
<div class="card-header pb-0 pt-1">
|
||||||
<h3 class="card-title">Power production</h3>
|
<h3 class="card-title">Power production</h3>
|
||||||
<div class="card-tools">
|
<div class="card-tools">
|
||||||
<button type="button" class="btn btn-tool" title="Voriger Tag" onclick="prevDay()">
|
<button type="button" class="btn btn-tool" title="Voriger Tag" onclick="prevDay()">
|
||||||
<i class="bi bi-skip-backward"></i>
|
<i class="bi bi-skip-backward"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" type="btn btn-tool" class="btn btn-tool datepicker-native">
|
<button type="button" type="btn btn-tool" class="btn btn-tool datepicker-native">
|
||||||
<i class="bi bi-calendar-week"></i>
|
<i class="bi bi-calendar-week"></i>
|
||||||
<input type="date" id="DatePickerProd" class="datepicker-native-input" onInput="changeDay(event);" />
|
<input type="date" id="DatePickerProd" class="datepicker-native-input" onInput="changeDay(event);" />
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-tool" title="Nächster Tag" onclick="nextDay()">
|
<button type="button" class="btn btn-tool" title="Nächster Tag" onclick="nextDay()">
|
||||||
<i class="bi bi-skip-forward"></i>
|
<i class="bi bi-skip-forward"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
<i class="bi bi-x-lg"></i>
|
<i class="bi bi-x-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body pb-1">
|
<div class="card-body pb-1">
|
||||||
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
<div class="chart-container" style="position: relative; height:100%; width:100%">
|
||||||
<canvas id="production-chart" height="400px;"></canvas>
|
<canvas id="production-chart" height="400px;"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card -->
|
<!-- /.card -->
|
||||||
</div>
|
</div>
|
||||||
<!-- /.Start col -->
|
<!-- /.Start col -->
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<?php include __DIR__ . "/weather_cards.html"; ?>
|
||||||
<!-- Start col -->
|
<!-- /.row (main row) -->
|
||||||
<div class="m-0 col-xl-2 col-4 d-flex">
|
</div>
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
<!--end::Container-->
|
||||||
<div class="card-header pb-0 pt-1">
|
</div>
|
||||||
<h3 class="card-title">Temp.</h3>
|
<!--end::App Content-->
|
||||||
</div>
|
</main>
|
||||||
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
|
||||||
<h3 id="temp">--</h3>°C
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="m-0 col-xl-2 col-4 d-flex">
|
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Feuchte</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
|
||||||
<h3 id="humidity">--</h3>%rF
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="m-0 col-xl-2 col-4 d-flex">
|
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Wind</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
|
||||||
<div id="windDir" class="winddir" style="transform: rotate(180deg);"></div>
|
|
||||||
<h3 id="windSpd">--</h3>km/h
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="m-0 col-xl-2 col-4 d-flex">
|
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Böen</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
|
||||||
<div id="windDirGust" class="winddir" style="transform: rotate(180deg);"></div>
|
|
||||||
<h3 id="windGust">--</h3>km/h
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="m-0 col-xl-2 col-4 d-flex">
|
|
||||||
<div class="card p-0 mb-4" style="width:100%">
|
|
||||||
<div class="card-header pb-0 pt-1">
|
|
||||||
<h3 class="card-title">Druck</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
|
||||||
<h3 id="ambPress">--</h3>hPa
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- /.row (main row) -->
|
|
||||||
</div>
|
|
||||||
<!--end::Container-->
|
|
||||||
</div>
|
|
||||||
<!--end::App Content-->
|
|
||||||
</main>
|
|
||||||
<!--end::App Main-->
|
<!--end::App Main-->
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<!--begin::App Main-->
|
||||||
|
<main class="app-main">
|
||||||
|
<!--begin::App Content Header-->
|
||||||
|
<div class="app-content-header">
|
||||||
|
<!--begin::Container-->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<!--begin::Row-->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<h3 class="mb-0">Wetter</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--end::Row-->
|
||||||
|
</div>
|
||||||
|
<!--end::Container-->
|
||||||
|
</div>
|
||||||
|
<!--end::App Content Header-->
|
||||||
|
<!--begin::App Content-->
|
||||||
|
<div class="app-content">
|
||||||
|
<!--begin::Container-->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<?php include __DIR__ . "/weather_cards.html"; ?>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 d-flex align-items-stretch">
|
||||||
|
<div class="card p-0 mb-4" style="width:100%">
|
||||||
|
<div class="card-header pb-0 pt-1">
|
||||||
|
<h3 class="card-title">Vorhersage</h3>
|
||||||
|
<div class="card-tools">
|
||||||
|
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
|
||||||
|
<i class="bi bi-x-lg"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body pb-1" id="meteogram">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.card -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.row (main row) -->
|
||||||
|
</div>
|
||||||
|
<!--end::Container-->
|
||||||
|
</div>
|
||||||
|
<!--end::App Content-->
|
||||||
|
</main>
|
||||||
|
<!--end::App Main-->
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<!-- Wetterkacheln - eingebunden von solar.php, heat.php und weather.php.
|
||||||
|
Aktualisiert werden sie von updateWeatherCards() aus js/solar/common.js. -->
|
||||||
|
<div class="row">
|
||||||
|
<!-- Start col -->
|
||||||
|
<div class="m-0 col-xl-2 col-4 d-flex">
|
||||||
|
<div class="card p-0 mb-4" style="width:100%">
|
||||||
|
<div class="card-header pb-0 pt-1">
|
||||||
|
<h3 class="card-title">Temp.</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
||||||
|
<h3 id="temp">--</h3>°C
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="m-0 col-xl-2 col-4 d-flex">
|
||||||
|
<div class="card p-0 mb-4" style="width:100%">
|
||||||
|
<div class="card-header pb-0 pt-1">
|
||||||
|
<h3 class="card-title">Feuchte</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
||||||
|
<h3 id="humidity">--</h3>%rF
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="m-0 col-xl-2 col-4 d-flex">
|
||||||
|
<div class="card p-0 mb-4" style="width:100%">
|
||||||
|
<div class="card-header pb-0 pt-1">
|
||||||
|
<h3 class="card-title">Wind</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
||||||
|
<div id="windDir" class="winddir" style="transform: rotate(180deg);"></div>
|
||||||
|
<h3 id="windSpd">--</h3>km/h
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="m-0 col-xl-2 col-4 d-flex">
|
||||||
|
<div class="card p-0 mb-4" style="width:100%">
|
||||||
|
<div class="card-header pb-0 pt-1">
|
||||||
|
<h3 class="card-title">Böen</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
||||||
|
<div id="windDirGust" class="winddir" style="transform: rotate(180deg);"></div>
|
||||||
|
<h3 id="windGust">--</h3>km/h
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="m-0 col-xl-2 col-4 d-flex">
|
||||||
|
<div class="card p-0 mb-4" style="width:100%">
|
||||||
|
<div class="card-header pb-0 pt-1">
|
||||||
|
<h3 class="card-title">Druck</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-2 d-flex flex-column" id="realtimeSVGcontainer" style="position:relative;">
|
||||||
|
<h3 id="ambPress">--</h3>hPa
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||