modify filemode for linux

This commit is contained in:
m0@nas 2026-02-14 20:08:34 +01:00
parent 6f043386db
commit 851147ee2e
394 changed files with 114410 additions and 114410 deletions

98
.gitignore vendored
View File

@ -1,49 +1,49 @@
# Python # Python
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
*$py.class *$py.class
*.so *.so
.Python .Python
build/ build/
develop-eggs/ develop-eggs/
dist/ dist/
downloads/ downloads/
eggs/ eggs/
.eggs/ .eggs/
lib/ lib/
lib64/ lib64/
parts/ parts/
sdist/ sdist/
var/ var/
wheels/ wheels/
*.egg-info/ *.egg-info/
.installed.cfg .installed.cfg
*.egg *.egg
# Virtual Environment # Virtual Environment
venv/ venv/
ENV/ ENV/
env/ env/
# IDE # IDE
.vscode/ .vscode/
.idea/ .idea/
*.swp *.swp
*.swo *.swo
*~ *~
# Konfiguration (enthält Credentials!) # Konfiguration (enthält Credentials!)
config.ini config.ini
# Logs # Logs
*.log *.log
logs/ logs/
# Betriebssystem # Betriebssystem
.DS_Store .DS_Store
Thumbs.db Thumbs.db
# Temporäre Dateien # Temporäre Dateien
*.tmp *.tmp
*.bak *.bak
*.backup *.backup

View File

@ -1,16 +1,16 @@
<?php <?php
require_once("restricted/mysql.php"); require_once("restricted/mysql.php");
require_once("helper.php"); require_once("helper.php");
$mysql = new mysqli($mysql_server,$mysql_user,$mysql_pass,$mysql_db); $mysql = new mysqli($mysql_server,$mysql_user,$mysql_pass,$mysql_db);
if(!mysqli_query($mysql,"DELETE FROM addUser WHERE datetime < DATE_SUB(NOW(), INTERVAL 1 MINUTE);")){ if(!mysqli_query($mysql,"DELETE FROM addUser WHERE datetime < DATE_SUB(NOW(), INTERVAL 1 MINUTE);")){
echo mysqli_error($mysql); echo mysqli_error($mysql);
} }
if(isLocal()){ if(isLocal()){
$accessKey = strval(random_int(0,99999999)); $accessKey = strval(random_int(0,99999999));
if(!mysqli_query($mysql,"INSERT INTO addUser SET accesskey=".$accessKey.", datetime=NOW();")){ if(!mysqli_query($mysql,"INSERT INTO addUser SET accesskey=".$accessKey.", datetime=NOW();")){
echo mysqli_error($mysql); echo mysqli_error($mysql);
} }
header('Location: https://nas.el-wa.org/smart?addUser='.$accessKey); header('Location: https://nas.el-wa.org/smart?addUser='.$accessKey);
echo 'https://nas.el-wa.org/smart?addUser='.$accessKey; echo 'https://nas.el-wa.org/smart?addUser='.$accessKey;
} }
?> ?>

View File

@ -1,264 +1,264 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$close = 0; $close = 0;
function getSSLPage($url) { function getSSLPage($url) {
$curlSession = curl_init(); $curlSession = curl_init();
curl_setopt($curlSession, CURLOPT_URL, $url); curl_setopt($curlSession, CURLOPT_URL, $url);
curl_setopt($curlSession, CURLOPT_BINARYTRANSFER, true); curl_setopt($curlSession, CURLOPT_BINARYTRANSFER, true);
curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true); curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true);
$jsonData = json_decode(curl_exec($curlSession),true); $jsonData = json_decode(curl_exec($curlSession),true);
curl_close($curlSession); curl_close($curlSession);
return $jsonData; 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
if(isset($_POST["floor"])){ if(isset($_POST["floor"])){
switch($_POST["floor"]){ switch($_POST["floor"]){
case "UG": case "UG":
$floor = "UG"; $floor = "UG";
break; break;
case "EG": case "EG":
$floor = "EG"; $floor = "EG";
break; break;
case "OG": case "OG":
$floor = "OG"; $floor = "OG";
break; break;
default: default:
$floor = ""; $floor = "";
} }
}else{ }else{
$floor = ""; $floor = "";
} }
if(isset($_POST["tSpanFrom"])){ if(isset($_POST["tSpanFrom"])){
$tFrom = date("Y-m-d H:i:s",strtotime($_POST["tSpanFrom"])); $tFrom = date("Y-m-d H:i:s",strtotime($_POST["tSpanFrom"]));
}else{ }else{
$tFrom = "00:10:00"; $tFrom = "00:10:00";
} }
if(isset($_POST["tSpanTo"])){ if(isset($_POST["tSpanTo"])){
$tTo = date("Y-m-d H:i:s",strtotime($_POST["tSpanTo"])); $tTo = date("Y-m-d H:i:s",strtotime($_POST["tSpanTo"]));
}else{ }else{
$tTo = "23:59:00"; $tTo = "23:59:00";
} }
if(isset($_POST["runOnce"])){ if(isset($_POST["runOnce"])){
$force = true; $force = true;
}else{ }else{
$force = false; $force = false;
} }
if(isset($_POST["actMo"])){$mo = true;}else{$mo = false;} if(isset($_POST["actMo"])){$mo = true;}else{$mo = false;}
if(isset($_POST["actDi"])){$di = true;}else{$di = false;} if(isset($_POST["actDi"])){$di = true;}else{$di = false;}
if(isset($_POST["actMi"])){$mi = true;}else{$mi = false;} if(isset($_POST["actMi"])){$mi = true;}else{$mi = false;}
if(isset($_POST["actDo"])){$do = true;}else{$do = false;} if(isset($_POST["actDo"])){$do = true;}else{$do = false;}
if(isset($_POST["actFr"])){$fr = true;}else{$fr = false;} if(isset($_POST["actFr"])){$fr = true;}else{$fr = false;}
if(isset($_POST["actSa"])){$sa = true;}else{$sa = false;} if(isset($_POST["actSa"])){$sa = true;}else{$sa = false;}
if(isset($_POST["actSo"])){$so = true;}else{$so = false;} if(isset($_POST["actSo"])){$so = true;}else{$so = false;}
if(isset($_POST["actFerien"])){$ferien = true;}else{$ferien = false;} if(isset($_POST["actFerien"])){$ferien = true;}else{$ferien = false;}
if(isset($_POST["actFeier"])){$feiertag = true;}else{$feiertag = false;} if(isset($_POST["actFeier"])){$feiertag = true;}else{$feiertag = false;}
$close = 0; $close = 0;
if(isset($_POST["changeID"])){ if(isset($_POST["changeID"])){
$id = intval($_POST["changeID"]); $id = intval($_POST["changeID"]);
if($_POST["changeID"] != "0" && $id == 0){ if($_POST["changeID"] != "0" && $id == 0){
$id = -1; $id = -1;
} }
}else{ }else{
$id = -1; $id = -1;
} }
$id = 2; $id = 2;
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
if($id > -1){ if($id > -1){
$qry = "UPDATE autoActions SET $qry = "UPDATE autoActions SET
`floor` = '".$floor."', `window_from`= '".$tFrom."', `window_to` = '".$tTo."', `floor` = '".$floor."', `window_from`= '".$tFrom."', `window_to` = '".$tTo."',
`force_once` = '".$force."', `mo` = '".$mo."', `di` = '".$di."', `mi` = '".$mi."', `force_once` = '".$force."', `mo` = '".$mo."', `di` = '".$di."', `mi` = '".$mi."',
`do` = '".$do."', `fr` = '".$fr."', `sa` = '".$sa."', `so` = '".$so."', `do` = '".$do."', `fr` = '".$fr."', `sa` = '".$sa."', `so` = '".$so."',
`ferien` = '".$ferien."', `feiertag` = '".$feiertag."' WHERE id=".$id.";"; `ferien` = '".$ferien."', `feiertag` = '".$feiertag."' WHERE id=".$id.";";
mysqli_query($mysql, $qry); mysqli_query($mysql, $qry);
mysqli_query($mysql, "DELETE FROM autoactionsActors WHERE actionID=".$id.";"); mysqli_query($mysql, "DELETE FROM autoactionsActors WHERE actionID=".$id.";");
mysqli_query($mysql, "DELETE FROM autoactionsSensors WHERE actionID=".$id.";"); mysqli_query($mysql, "DELETE FROM autoactionsSensors WHERE actionID=".$id.";");
$actionID = $id; $actionID = $id;
}else{ }else{
$qry = "INSERT into autoActions $qry = "INSERT into autoActions
(`id`, `floor`, `window_from`, `window_to`, `force_once`, `mo`, `di`, `mi`, `do`, `fr`, `sa`, `so`, `ferien`, `feiertag`, `last_run`) (`id`, `floor`, `window_from`, `window_to`, `force_once`, `mo`, `di`, `mi`, `do`, `fr`, `sa`, `so`, `ferien`, `feiertag`, `last_run`)
VALUES (NULL, '".$floor."', '".$tFrom."', '".$tTo."', '".$force."', '".$mo."', '".$di."', '".$mi."', '".$do."', '".$fr."', '".$sa."', '".$so."', '".$ferien."', '".$feiertag."', '2020-01-01 12:00:00.000000')"; VALUES (NULL, '".$floor."', '".$tFrom."', '".$tTo."', '".$force."', '".$mo."', '".$di."', '".$mi."', '".$do."', '".$fr."', '".$sa."', '".$so."', '".$ferien."', '".$feiertag."', '2020-01-01 12:00:00.000000')";
mysqli_query($mysql, $qry); mysqli_query($mysql, $qry);
$actionID = mysqli_insert_id($mysql); $actionID = mysqli_insert_id($mysql);
} }
//Get all Sensors: //Get all Sensors:
$num=1; $num=1;
while(isset($_POST["sensorSelect".$num])){ while(isset($_POST["sensorSelect".$num])){
$id = intval($_POST["sensorSelect".$num]); $id = intval($_POST["sensorSelect".$num]);
if($_POST["sensorSelect".$num] != "0" && $id == 0){ if($_POST["sensorSelect".$num] != "0" && $id == 0){
$id = -1; $id = -1;
} }
if(isset($_POST["btnLogic".$num])){ if(isset($_POST["btnLogic".$num])){
if(strtolower($_POST["btnLogic".$num]) == "oder"){ if(strtolower($_POST["btnLogic".$num]) == "oder"){
$weight = "or"; $weight = "or";
}else{ }else{
$weight = "and"; $weight = "and";
} }
}else{ }else{
$weight = "and"; $weight = "and";
} }
if (in_array($_POST["btnOperator".$num], array('+','-','=','&lt;','&gt;','!='))) { if (in_array($_POST["btnOperator".$num], array('+','-','=','&lt;','&gt;','!='))) {
$cond = $_POST["btnOperator".$num]; $cond = $_POST["btnOperator".$num];
}else{ }else{
$cond = "="; $cond = "=";
echo $_POST["btnOperator".$num]; echo $_POST["btnOperator".$num];
} }
echo $_POST["btnOperator".$num]; echo $_POST["btnOperator".$num];
$valID = intval($_POST["paramSelect".$num]); $valID = intval($_POST["paramSelect".$num]);
if($_POST["paramSelect".$num] != "0" && $id == 0){ if($_POST["paramSelect".$num] != "0" && $id == 0){
$valID = -1; $valID = -1;
} }
$state = mysqli_real_escape_string($mysql, $_POST["threshold".$num]); $state = mysqli_real_escape_string($mysql, $_POST["threshold".$num]);
$qry = "INSERT INTO `autoactionsSensors` $qry = "INSERT INTO `autoactionsSensors`
(`id`, `sensorID`, `state`, `valID`, `condType`, `link`, `actionID`) (`id`, `sensorID`, `state`, `valID`, `condType`, `link`, `actionID`)
VALUES (NULL, '".$id."', '".$state."', '".$valID."', '".$cond."', '".$weight."', '".$actionID."')"; VALUES (NULL, '".$id."', '".$state."', '".$valID."', '".$cond."', '".$weight."', '".$actionID."')";
mysqli_query($mysql, $qry); mysqli_query($mysql, $qry);
$num++; $num++;
} }
$close=1; $close=1;
} }
} else { } else {
$close = 1; $close = 1;
} }
if (!$close) { if (!$close) {
echo <<<ENDE echo <<<ENDE
<style> <style>
input[type='range']::-webkit-slider-runnable-track { input[type='range']::-webkit-slider-runnable-track {
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7; background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
background-size: var(--background-size, 0%) 100%; background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
</style> </style>
<!--begin::Form--> <!--begin::Form-->
<form id="heater_form"> <form id="heater_form">
<div class="accordion" id="actionAccordion"> <div class="accordion" id="actionAccordion">
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header" id="headingOne"> <h2 class="accordion-header" id="headingOne">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
<i class="bi bi-lightning-fill"></i> &nbsp;&nbsp;Auslöser <i class="bi bi-lightning-fill"></i> &nbsp;&nbsp;Auslöser
</button> </button>
</h2> </h2>
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#actionAccordion"> <div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#actionAccordion">
<div class="accordion-body" id="sensorsList"> <div class="accordion-body" id="sensorsList">
<div class="input-group mb-1" id="sensorSettings1"> <div class="input-group mb-1" id="sensorSettings1">
<div class="form-floating"> <div class="form-floating">
<select class="form-select" id="sensorSelect1" name="sensorSelect1" aria-label="Default select example"> <select class="form-select" id="sensorSelect1" name="sensorSelect1" aria-label="Default select example">
</select> </select>
<label for="sensorSelect1">Sensor</label> <label for="sensorSelect1">Sensor</label>
</div> </div>
<div class="form-floating" id="paramBlock1"> <div class="form-floating" id="paramBlock1">
<select class="form-select" id="paramSelect1" name="paramSelect1" aria-label="Default select example"> <select class="form-select" id="paramSelect1" name="paramSelect1" aria-label="Default select example">
</select> </select>
<label for="paramSelect1">Messwert</label> <label for="paramSelect1">Messwert</label>
</div> </div>
<button class="btn btn-outline-secondary " type="button" id="btnOperator1" name="btnOperator1">&gt;</button> <button class="btn btn-outline-secondary " type="button" id="btnOperator1" name="btnOperator1">&gt;</button>
<div class="form-floating" id="valBlock1"> <div class="form-floating" id="valBlock1">
<input type="number" class="form-control" id="threshold1" placeholder="0" value="0" name="threshold1"></input> <input type="number" class="form-control" id="threshold1" placeholder="0" value="0" name="threshold1"></input>
<label for="threshold1">Wert/Schwelle</label> <label for="threshold1">Wert/Schwelle</label>
</div> </div>
</div> </div>
</div> </div>
<button class="btn btn-outline-success btn-sm" type="button" id="btnAddSensor"><i class="bi bi-plus-lg"></i></button> <button class="btn btn-outline-success btn-sm" type="button" id="btnAddSensor"><i class="bi bi-plus-lg"></i></button>
</div> </div>
</div> </div>
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header" id="headingTwo"> <h2 class="accordion-header" id="headingTwo">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
<i class="bi bi-calendar-check-fill"></i> &nbsp;&nbsp;Bedingungen <i class="bi bi-calendar-check-fill"></i> &nbsp;&nbsp;Bedingungen
</button> </button>
</h2> </h2>
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#actionAccordion"> <div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#actionAccordion">
<div class="accordion-body"> <div class="accordion-body">
<div class="input-group mb-3" id="timespan"> <div class="input-group mb-3" id="timespan">
<span class="input-group-text">Aktiver Zeitraum: </span> <span class="input-group-text">Aktiver Zeitraum: </span>
<div class="form-floating"> <div class="form-floating">
<input type="time" class="form-control" id="tSpanFrom" name="tSpanFrom" placeholder="0" value="00:00"></input> <input type="time" class="form-control" id="tSpanFrom" name="tSpanFrom" placeholder="0" value="00:00"></input>
<label>Von</label> <label>Von</label>
</div> </div>
<div class="form-floating"> <div class="form-floating">
<input type="time" class="form-control" id="tSpanTo" name="tSpanTo" placeholder="0" value="23:59"></input> <input type="time" class="form-control" id="tSpanTo" name="tSpanTo" placeholder="0" value="23:59"></input>
<label>Bis</label> <label>Bis</label>
</div> </div>
</div> </div>
Aktive Wochentage: Aktive Wochentage:
<div class="input-group mb-3" id="timespan"> <div class="input-group mb-3" id="timespan">
<div class="input-group-text"> <div class="input-group-text">
<input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actMo" name="actMo"><label class="form-check-label" for="actMo">Mo</label> <input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actMo" name="actMo"><label class="form-check-label" for="actMo">Mo</label>
</div> </div>
<div class="input-group-text"> <div class="input-group-text">
<input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actDi" name="actDi"><label class="form-check-label" for="actDi">Di</label> <input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actDi" name="actDi"><label class="form-check-label" for="actDi">Di</label>
</div> </div>
<div class="input-group-text"> <div class="input-group-text">
<input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actMi" name="actMi"><label class="form-check-label" for="actMi">Mi</label> <input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actMi" name="actMi"><label class="form-check-label" for="actMi">Mi</label>
</div> </div>
<div class="input-group-text"> <div class="input-group-text">
<input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actDo" name="actDo"><label class="form-check-label" for="actDo">Do</label> <input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actDo" name="actDo"><label class="form-check-label" for="actDo">Do</label>
</div> </div>
<div class="input-group-text"> <div class="input-group-text">
<input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actFr" name="actFr"><label class="form-check-label" for="actFr">Fr</label> <input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actFr" name="actFr"><label class="form-check-label" for="actFr">Fr</label>
</div> </div>
<div class="input-group-text"> <div class="input-group-text">
<input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actSa" name="actSa"><label class="form-check-label" for="actSa">Sa</label> <input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actSa" name="actSa"><label class="form-check-label" for="actSa">Sa</label>
</div> </div>
<div class="input-group-text"> <div class="input-group-text">
<input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actSo" name="actSo"><label class="form-check-label" for="actSo">So</label> <input class="form-check-input mt-0 me-1" type="checkbox" value="1" id="actSo" name="actSo"><label class="form-check-label" for="actSo">So</label>
</div> </div>
</div> </div>
Ferien/Feiertage: Ferien/Feiertage:
<div class="input-group mb-3" id="timespan"> <div class="input-group mb-3" id="timespan">
<div class="input-group-text"> <div class="input-group-text">
<input class="form-check-input mt-0 me-2" type="checkbox" value="1" id="actFerien" name="actFerien"><label class="form-check-label" for="actFerien">In den Ferien ausführen</label> <input class="form-check-input mt-0 me-2" type="checkbox" value="1" id="actFerien" name="actFerien"><label class="form-check-label" for="actFerien">In den Ferien ausführen</label>
</div> </div>
<div class="input-group-text"> <div class="input-group-text">
<input class="form-check-input mt-0 me-2" type="checkbox" value="1" id="actFeier" name="actFeier"><label class="form-check-label" for="actFeier">An Feiertagen ausführen</label> <input class="form-check-input mt-0 me-2" type="checkbox" value="1" id="actFeier" name="actFeier"><label class="form-check-label" for="actFeier">An Feiertagen ausführen</label>
</div> </div>
</div> </div>
Falls die Bedingung bis zuletzt nicht erfüllt wurde: Falls die Bedingung bis zuletzt nicht erfüllt wurde:
<div class="input-group mb-3" id="timespan"> <div class="input-group mb-3" id="timespan">
<div class="input-group-text"> <div class="input-group-text">
<input class="form-check-input mt-0 me-2" type="checkbox" value="1" id="runOnce" name="runOnce"><label class="form-check-label" for="runOnce">Auf jeden Fall zu Ende des aktiven Zeitraums ausführen</label> <input class="form-check-input mt-0 me-2" type="checkbox" value="1" id="runOnce" name="runOnce"><label class="form-check-label" for="runOnce">Auf jeden Fall zu Ende des aktiven Zeitraums ausführen</label>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header" id="headingThree"> <h2 class="accordion-header" id="headingThree">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
<i class="bi bi-play-fill"></i> &nbsp;&nbsp;Aktionen <i class="bi bi-play-fill"></i> &nbsp;&nbsp;Aktionen
</button> </button>
</h2> </h2>
<div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#actionAccordion"> <div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#actionAccordion">
<div class="accordion-body"> <div class="accordion-body">
<div class="accordion-body" id="actorsList"> <div class="accordion-body" id="actorsList">
<div class="input-group mb-3" id="actorSettings1"> <div class="input-group mb-3" id="actorSettings1">
<div class="form-floating"> <div class="form-floating">
<select class="form-select" id="actorSelect1" name="actorSelect1"> <select class="form-select" id="actorSelect1" name="actorSelect1">
</select> </select>
<label for="actorSelect1">Aktor</label> <label for="actorSelect1">Aktor</label>
</div> </div>
<div class="form-floating" id="actParamBlock1"> <div class="form-floating" id="actParamBlock1">
<select class="form-select" id="actParamSelect1" name="actParamSelect1"> <select class="form-select" id="actParamSelect1" name="actParamSelect1">
</select> </select>
<label for="paramSelect1">Eigenschaft</label> <label for="paramSelect1">Eigenschaft</label>
</div> </div>
<button class="btn btn-outline-secondary " type="button" id="btnActOperator1" name="btnActOperator1">&gt;</button> <button class="btn btn-outline-secondary " type="button" id="btnActOperator1" name="btnActOperator1">&gt;</button>
<div class="form-floating" id="actValBlock1"> <div class="form-floating" id="actValBlock1">
<input type="number" class="form-control" id="actValue1" name="actValue1" placeholder="0" value="0"></input> <input type="number" class="form-control" id="actValue1" name="actValue1" placeholder="0" value="0"></input>
<label for="actValue1">Sollwert</label> <label for="actValue1">Sollwert</label>
</div> </div>
</div> </div>
</div> </div>
<button class="btn btn-outline-success btn-sm" type="button" id="btnAddActor"><i class="bi bi-plus-lg"></i></button> <button class="btn btn-outline-success btn-sm" type="button" id="btnAddActor"><i class="bi bi-plus-lg"></i></button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
ENDE; ENDE;
} }

View File

@ -1,12 +1,12 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
if(isset($_GET["actorID"])){ if(isset($_GET["actorID"])){
$ID = intval($_GET["actorID"]); $ID = intval($_GET["actorID"]);
$qry = "SELECT parameters FROM actors WHERE id=".$ID; $qry = "SELECT parameters FROM actors WHERE id=".$ID;
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $qry); $result = mysqli_query($mysql, $qry);
echo $result->fetch_array()[0]; echo $result->fetch_array()[0];
} }
?> ?>

View File

@ -1,141 +1,141 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
if (checkLogin()) { if (checkLogin()) {
chdir("/volume1/homes/wagner/"); chdir("/volume1/homes/wagner/");
putenv('PYTHONPATH="/var/services/homes/wagner/.local/lib/python3.8/site-packages/'); putenv('PYTHONPATH="/var/services/homes/wagner/.local/lib/python3.8/site-packages/');
$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;
exec("python wattpilot.py -start 2>&1", $output, $return_var); exec("python wattpilot.py -start 2>&1", $output, $return_var);
} elseif ($_POST["evStart/Stop"] == "Laden stoppen") { } elseif ($_POST["evStart/Stop"] == "Laden stoppen") {
$close = 1; $close = 1;
exec("python wattpilot.py -stop 2>&1", $output, $return_var); exec("python wattpilot.py -stop 2>&1", $output, $return_var);
} }
$close = 1; $close = 1;
} else if (isset($_POST["evMode"])) { } else if (isset($_POST["evMode"])) {
if ($_POST["fte"] > 100) if ($_POST["fte"] > 100)
$_POST["fte"] = 100; $_POST["fte"] = 100;
else if ($_POST["fte"] < 1) else if ($_POST["fte"] < 1)
$_POST["fte"] = 1; $_POST["fte"] = 1;
if ($_POST["evAmp"] > 16) if ($_POST["evAmp"] > 16)
$_POST["evAmp"] = 16; $_POST["evAmp"] = 16;
if ($_POST["evAmp"] < 6) if ($_POST["evAmp"] < 6)
$_POST["evAmp"] = 6; $_POST["evAmp"] = 6;
$_POST["fte"] = $_POST["fte"] * 140; $_POST["fte"] = $_POST["fte"] * 140;
if ($_POST["evMode"] == "eco") { if ($_POST["evMode"] == "eco") {
$close = 1; $close = 1;
if ($_POST["ftt"] && $_POST["fte"] > 0) { if ($_POST["ftt"] && $_POST["fte"] > 0) {
exec("python wattpilot.py -eco -time " . $_POST["ftt"] . " -energy " . $_POST["fte"] . " -maxCurr " . $_POST["evAmp"] . " -setTime " . gmdate("Y-m-d\TH:i:s", time()) . ".000 2>&1", $output, $return_var); exec("python wattpilot.py -eco -time " . $_POST["ftt"] . " -energy " . $_POST["fte"] . " -maxCurr " . $_POST["evAmp"] . " -setTime " . gmdate("Y-m-d\TH:i:s", time()) . ".000 2>&1", $output, $return_var);
} else { } else {
exec("/bin/python wattpilot.py -e 2>&1", $output, $return_var); exec("/bin/python wattpilot.py -e 2>&1", $output, $return_var);
} }
} 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) {
exec("python wattpilot.py -default -time " . $_POST["ftt"] . " -energy " . $_POST["fte"] . " -maxCurr " . $_POST["evAmp"] . " -setTime " . gmdate("Y-m-d\TH:i:s", time()) . ".000 2>&1", $output, $return_var); exec("python wattpilot.py -default -time " . $_POST["ftt"] . " -energy " . $_POST["fte"] . " -maxCurr " . $_POST["evAmp"] . " -setTime " . gmdate("Y-m-d\TH:i:s", time()) . ".000 2>&1", $output, $return_var);
} else { } else {
exec("python wattpilot.py -d 2>&1", $output, $return_var); exec("python wattpilot.py -d 2>&1", $output, $return_var);
} }
} 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) {
exec("python wattpilot.py -trip -time " . $_POST["ftt"] . " -energy " . $_POST["fte"] . " -maxCurr " . $_POST["evAmp"] . " -setTime " . gmdate("Y-m-d\TH:i:s", time()) . ".000 2>&1", $output, $return_var); exec("python wattpilot.py -trip -time " . $_POST["ftt"] . " -energy " . $_POST["fte"] . " -maxCurr " . $_POST["evAmp"] . " -setTime " . gmdate("Y-m-d\TH:i:s", time()) . ".000 2>&1", $output, $return_var);
} else { } else {
exec("python wattpilot.py -t 2>&1", $output, $return_var); exec("python wattpilot.py -t 2>&1", $output, $return_var);
} }
} }
$close = 1; $close = 1;
} }
} else { } else {
$close = 1; $close = 1;
} }
if (!$close) { if (!$close) {
echo <<<ENDE echo <<<ENDE
<style> <style>
input[type='range']::-webkit-slider-runnable-track { input[type='range']::-webkit-slider-runnable-track {
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7; background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
background-size: var(--background-size, 0%) 100%; background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
</style> </style>
<div class="d-grid gap-2 col-6 mx-auto my-4"> <div class="d-grid gap-2 col-6 mx-auto my-4">
<button class="btn btn-primary" id="evStart/Stop">Laden starten</button> <button class="btn btn-primary" id="evStart/Stop">Laden starten</button>
</div> </div>
<!--begin::Form--> <!--begin::Form-->
<form id="carEG_form"> <form id="carEG_form">
<div class="card m-3"> <div class="card m-3">
<div class="card-header py-1 px-3"> <div class="card-header py-1 px-3">
<div class="card-title">Modus</div> <div class="card-title">Modus</div>
</div> </div>
<!--begin::Body--> <!--begin::Body-->
<div class="card-body"> <div class="card-body">
<div class="col-sm-10"> <div class="col-sm-10">
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="evMode" id="EV_Default" value="default"> <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> <label class="form-check-label" for="EV_Default"> Immer Laden </label></input>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="evMode" id="EV_Eco" value="eco"> <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> <label class="form-check-label" for="EV_Eco"> Überschuss </label></input>
</div> </div>
<div class="form-check disabled"> <div class="form-check disabled">
<input class="form-check-input" type="radio" name="evMode" id="EV_NextTrip" value="NextTrip"> <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> <label class="form-check-label" for="EV_NextTrip"> Ladeplanung </label></input>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="card m-3"> <div class="card m-3">
<div class="card-header py-1 px-3"> <div class="card-header py-1 px-3">
<div class="card-title">Max. Ladestrom</div> <div class="card-title">Max. Ladestrom</div>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="col-sm-10"> <div class="col-sm-10">
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="evAmp" id="EV_6A" value="6"> <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> <label class="form-check-label" for="EV_6A"> 6A </label></input>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="evAmp" id="EV_10A" value="10"> <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> <label class="form-check-label" for="EV_10A"> 10A </label></input>
</div> </div>
<div class="form-check disabled"> <div class="form-check disabled">
<input class="form-check-input" type="radio" name="evAmp" id="EV_16A" value="16"> <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> <label class="form-check-label" for="EV_16A"> 16A </label></input>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="card m-3"> <div class="card m-3">
<div class="card-header py-1 px-3"> <div class="card-header py-1 px-3">
<div class="card-title">Ladeplanung</div> <div class="card-title">Ladeplanung</div>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="row mb-3"> <div class="row mb-3">
<div class="form-check"> <div class="form-check">
<label class="form-label" for="addedCharge">Zusätzlich benötigte Ladung (%): </label> <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> <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" /> <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"> <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">1%</span>
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">100%</span> <span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">100%</span>
</div> </div>
<!--<input name="fte" class="form-control" type="number" max="100" min="1" value="" />--> <!--<input name="fte" class="form-control" type="number" max="100" min="1" value="" />-->
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="form-check"> <div class="form-check">
<label class="form-label" for="planedTime">Zeitpunkt zudem geladen sein soll: </label> <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=""/> <input id="EV_NextTripTime" name="ftt" class="form-control" size="2" type="time" value=""/>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
ENDE; ENDE;
} }

View File

@ -1,148 +1,148 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
function getSSLPage($url) { function getSSLPage($url) {
$curlSession = curl_init(); $curlSession = curl_init();
curl_setopt($curlSession, CURLOPT_URL, $url); curl_setopt($curlSession, CURLOPT_URL, $url);
curl_setopt($curlSession, CURLOPT_BINARYTRANSFER, true); curl_setopt($curlSession, CURLOPT_BINARYTRANSFER, true);
curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true); curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true);
$jsonData = json_decode(curl_exec($curlSession),true); $jsonData = json_decode(curl_exec($curlSession),true);
curl_close($curlSession); curl_close($curlSession);
return $jsonData; 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"); getSSLPage("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"); getSSLPage("http://192.168.179.122/api/set?frc=1");
} }
$close = 1; $close = 1;
} else if (isset($_POST["evMode"])) { } else if (isset($_POST["evMode"])) {
if ($_POST["fte"] > 100) if ($_POST["fte"] > 100)
$_POST["fte"] = 100; $_POST["fte"] = 100;
else if ($_POST["fte"] < 0) else if ($_POST["fte"] < 0)
$_POST["fte"] = 0; $_POST["fte"] = 0;
if ($_POST["evAmp"] > 16) if ($_POST["evAmp"] > 16)
$_POST["evAmp"] = 16; $_POST["evAmp"] = 16;
if ($_POST["evAmp"] < 6) if ($_POST["evAmp"] < 6)
$_POST["evAmp"] = 6; $_POST["evAmp"] = 6;
$_POST["fte"] = $_POST["fte"] * 90; $_POST["fte"] = $_POST["fte"] * 90;
$seconds = strtotime('1970-01-01 ' . $_POST["ftt"] . ':00GMT'); $seconds = strtotime('1970-01-01 ' . $_POST["ftt"] . ':00GMT');
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 . "&amp=" . $_POST["evAmp"] . "&fup=true&lmo=4"); getSSLPage("http://192.168.179.122/api/set?ate=" . $_POST["fte"] . "&att=" . $seconds . "&amp=" . $_POST["evAmp"] . "&fup=true&lmo=4");
} else { } else {
getSSLPage("http://192.168.179.122/api/set?amp=" . $_POST["evAmp"] . "&fup=true&lmo=4"); getSSLPage("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 . "&amp=" . $_POST["evAmp"] . "&fup=true&lmo=3"); getSSLPage("http://192.168.179.122/api/set?ate=" . $_POST["fte"] . "&att=" . $seconds . "&amp=" . $_POST["evAmp"] . "&fup=true&lmo=3");
} else { } else {
getSSLPage("http://192.168.179.122/api/set?amp=" . $_POST["evAmp"] . "&fup=true&lmo=3"); getSSLPage("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 . "&amp=" . $_POST["evAmp"] . "&fup=true&lmo=5"); getSSLPage("http://192.168.179.122/api/set?ate=" . $_POST["fte"] . "&att=" . $seconds . "&amp=" . $_POST["evAmp"] . "&fup=true&lmo=5");
} else { } else {
getSSLPage("http://192.168.179.122/api/set?amp=" . $_POST["evAmp"] . "&fup=true&lmo=5"); getSSLPage("http://192.168.179.122/api/set?amp=" . $_POST["evAmp"] . "&fup=true&lmo=5");
} }
} }
$close = 1; $close = 1;
} }
} else { } else {
$close = 1; $close = 1;
} }
if (!$close) { if (!$close) {
echo <<<ENDE echo <<<ENDE
<style> <style>
input[type='range']::-webkit-slider-runnable-track { input[type='range']::-webkit-slider-runnable-track {
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7; background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
background-size: var(--background-size, 0%) 100%; background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
</style> </style>
<div class="d-grid gap-2 col-6 mx-auto my-4"> <div class="d-grid gap-2 col-6 mx-auto my-4">
<button class="btn btn-primary" id="evStart/Stop">Laden starten</button> <button class="btn btn-primary" id="evStart/Stop">Laden starten</button>
</div> </div>
<!--begin::Form--> <!--begin::Form-->
<form id="carOG_form"> <form id="carOG_form">
<div class="card m-3"> <div class="card m-3">
<div class="card-header py-1 px-3"> <div class="card-header py-1 px-3">
<div class="card-title">Modus</div> <div class="card-title">Modus</div>
</div> </div>
<!--begin::Body--> <!--begin::Body-->
<div class="card-body"> <div class="card-body">
<div class="col-sm-10"> <div class="col-sm-10">
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="evMode" id="EV_Default" value="default"> <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> <label class="form-check-label" for="EV_Default"> Immer Laden </label></input>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="evMode" id="EV_Eco" value="eco"> <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> <label class="form-check-label" for="EV_Eco"> Überschuss </label></input>
</div> </div>
<div class="form-check disabled"> <div class="form-check disabled">
<input class="form-check-input" type="radio" name="evMode" id="EV_NextTrip" value="NextTrip"> <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> <label class="form-check-label" for="EV_NextTrip"> Ladeplanung </label></input>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="card m-3"> <div class="card m-3">
<div class="card-header py-1 px-3"> <div class="card-header py-1 px-3">
<div class="card-title">Max. Ladestrom</div> <div class="card-title">Max. Ladestrom</div>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="col-sm-10"> <div class="col-sm-10">
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="evAmp" id="EV_6A" value="6"> <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> <label class="form-check-label" for="EV_6A"> 6A </label></input>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="evAmp" id="EV_10A" value="10"> <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> <label class="form-check-label" for="EV_10A"> 10A </label></input>
</div> </div>
<div class="form-check disabled"> <div class="form-check disabled">
<input class="form-check-input" type="radio" name="evAmp" id="EV_16A" value="16"> <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> <label class="form-check-label" for="EV_16A"> 16A </label></input>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="card m-3"> <div class="card m-3">
<div class="card-header py-1 px-3"> <div class="card-header py-1 px-3">
<div class="card-title">Ladeplanung</div> <div class="card-title">Ladeplanung</div>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="row mb-3"> <div class="row mb-3">
<div class="form-check"> <div class="form-check">
<label class="form-label" for="addedCharge">Zusätzlich benötigte Ladung (%): </label> <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> <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" /> <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"> <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">1%</span>
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">100%</span> <span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">100%</span>
</div> </div>
<!--<input name="fte" class="form-control" type="number" max="100" min="1" value="" />--> <!--<input name="fte" class="form-control" type="number" max="100" min="1" value="" />-->
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="form-check"> <div class="form-check">
<label class="form-label" for="planedTime">Zeitpunkt zudem geladen sein soll: </label> <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=""/> <input id="EV_NextTripTime" name="ftt" class="form-control" size="2" type="time" value=""/>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
ENDE; ENDE;
} }

View File

@ -1,11 +1,11 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$qry = "SELECT name, id FROM actors"; $qry = "SELECT name, id FROM actors";
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $qry); $result = mysqli_query($mysql, $qry);
while($row = $result->fetch_assoc()){ while($row = $result->fetch_assoc()){
echo "<option value='".$row["id"]."'>".$row["name"]."</option>"; echo "<option value='".$row["id"]."'>".$row["name"]."</option>";
} }
?> ?>

View File

@ -1,11 +1,11 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$qry = "SELECT name, id FROM sensors"; $qry = "SELECT name, id FROM sensors";
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $qry); $result = mysqli_query($mysql, $qry);
while($row = $result->fetch_assoc()){ while($row = $result->fetch_assoc()){
echo "<option value='".$row["id"]."'>".$row["name"]."</option>"; echo "<option value='".$row["id"]."'>".$row["name"]."</option>";
} }
?> ?>

View File

@ -1,162 +1,162 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
if(!isset($_GET["TO"])){ if(!isset($_GET["TO"])){
$_GET["TO"] = 12; $_GET["TO"] = 12;
} }
$_GET["TO"] = intval($_GET["TO"]); $_GET["TO"] = intval($_GET["TO"]);
if(!isset($_GET["FROM"])){ if(!isset($_GET["FROM"])){
$_GET["FROM"] = -24; $_GET["FROM"] = -24;
} }
$_GET["FROM"] = intval($_GET["FROM"]); $_GET["FROM"] = intval($_GET["FROM"]);
//-totalConsumption-PL1_EV*1000-PL2_EV*1000-PL3_EV*1000-PL1_EVog*1000-PL2_EVog*1000-PL3_EVog*1000+PL1_OG+PL2_OG+PL3_OG-heaterPwr AS 'UG', //-totalConsumption-PL1_EV*1000-PL2_EV*1000-PL3_EV*1000-PL1_EVog*1000-PL2_EVog*1000-PL3_EVog*1000+PL1_OG+PL2_OG+PL3_OG-heaterPwr AS 'UG',
$consQuery = "SELECT $consQuery = "SELECT
UNIX_TIMESTAMP(EnergyFlow.datetime) AS time, UNIX_TIMESTAMP(EnergyFlow.datetime) AS time,
pvP AS 'Solarleistung', pvP AS 'Solarleistung',
soc AS Ladestand, soc AS Ladestand,
-totalConsumption-PL1_EV*1000-PL2_EV*1000-PL3_EV*1000-PL1_EVog*1000-PL2_EVog*1000-PL3_EVog*1000+PL1_OG+PL2_OG+PL3_OG-heaterPwr-PL1_UG-PL2_UG-PL3_UG-PL1_EG-PL2_EG-PL3_EG AS 'Gemein', -totalConsumption-PL1_EV*1000-PL2_EV*1000-PL3_EV*1000-PL1_EVog*1000-PL2_EVog*1000-PL3_EVog*1000+PL1_OG+PL2_OG+PL3_OG-heaterPwr-PL1_UG-PL2_UG-PL3_UG-PL1_EG-PL2_EG-PL3_EG AS 'Gemein',
(PL1_UG+PL2_UG+PL3_UG) AS 'UG', (PL1_UG+PL2_UG+PL3_UG) AS 'UG',
(PL1_EG+PL2_EG+PL3_EG) AS 'EG', (PL1_EG+PL2_EG+PL3_EG) AS 'EG',
-(PL1_OG+PL2_OG+PL3_OG) AS 'OG', -(PL1_OG+PL2_OG+PL3_OG) AS 'OG',
(PL1_EV+PL2_EV+PL3_EV)*1000 AS 'Auto UG', (PL1_EV+PL2_EV+PL3_EV)*1000 AS 'Auto UG',
(PL1_EVog+PL2_EVog+PL3_EVog)*1000 AS 'Auto OG', (PL1_EVog+PL2_EVog+PL3_EVog)*1000 AS 'Auto OG',
heaterPwr AS 'Heizstab', heaterPwr AS 'Heizstab',
IF(battP<0, -battP, 0) AS Batterieladung, IF(battP<0, -battP, 0) AS Batterieladung,
gridPfeed AS Einspeisung gridPfeed AS Einspeisung
FROM solarLog.EnergyFlow FROM solarLog.EnergyFlow
WHERE EnergyFlow.datetime BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"])." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR) WHERE EnergyFlow.datetime BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"])." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR)
ORDER BY EnergyFlow.datetime"; ORDER BY EnergyFlow.datetime";
$simQuery = "SELECT $simQuery = "SELECT
UNIX_TIMESTAMP(simPower.period_end) AS time, UNIX_TIMESTAMP(simPower.period_end) AS time,
power*1000 AS 'Vorhersage' power*1000 AS 'Vorhersage'
FROM solarLog.simPower FROM solarLog.simPower
WHERE simPower.period_end BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"])." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR) WHERE simPower.period_end BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"])." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR)
ORDER BY simPower.period_end"; ORDER BY simPower.period_end";
$linecolors["Solarleistung"] = "#FFFF00"; $linecolors["Solarleistung"] = "#FFFF00";
$linecolors["Gemein"] = "#FF9900"; $linecolors["Gemein"] = "#FF9900";
$linecolors["UG"] = "#FF8800"; $linecolors["UG"] = "#FF8800";
$linecolors["EG"] = "#FF6600"; $linecolors["EG"] = "#FF6600";
$linecolors["OG"] = "#FF4400"; $linecolors["OG"] = "#FF4400";
$linecolors["Auto UG"] = "#00aaFF"; $linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF"; $linecolors["Auto OG"] = "#0044FF";
$linecolors["Heizstab"] = "#FF0000"; $linecolors["Heizstab"] = "#FF0000";
$linecolors["Batterieladung"] = "#00aa00"; $linecolors["Batterieladung"] = "#00aa00";
$linecolors["Einspeisung"] = "#b0b0b0"; $linecolors["Einspeisung"] = "#b0b0b0";
$linecolors["Ladestand"] = "#00aa00"; $linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#2222FF"; $linecolors["Vorhersage"] = "#2222FF";
if (checkLogin()) { if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $consQuery); $result = mysqli_query($mysql, $consQuery);
$simRes = mysqli_query($mysql,$simQuery); $simRes = mysqli_query($mysql,$simQuery);
if(!$result){ if(!$result){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
$obj = (object)[]; // Cast empty array to object $obj = (object)[]; // Cast empty array to object
$obj->labels = []; $obj->labels = [];
$obj->datasets = []; $obj->datasets = [];
$i = 0; $i = 0;
$filled = 0; $filled = 0;
if ($simRes->num_rows > 1) { if ($simRes->num_rows > 1) {
$dataset = (object)[]; $dataset = (object)[];
$row1 = $simRes->fetch_assoc(); $row1 = $simRes->fetch_assoc();
$dataset->borderColor = $linecolors["Vorhersage"]; $dataset->borderColor = $linecolors["Vorhersage"];
$dataset->backgroundColor = $linecolors["Vorhersage"]."55"; $dataset->backgroundColor = $linecolors["Vorhersage"]."55";
$dataset->borderWidth=1.5; $dataset->borderWidth=1.5;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
$dataset->stack = "sim"; $dataset->stack = "sim";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
$dataset->label = "Vorhersage"; $dataset->label = "Vorhersage";
/*$pt = (object)[]; /*$pt = (object)[];
$pt->x = $row1["time"]*1000; $pt->x = $row1["time"]*1000;
$pt->y = $row1["Vorhersage"]; $pt->y = $row1["Vorhersage"];
$dataset->data[] = clone $pt; $dataset->data[] = clone $pt;
while ($row1 = $simRes->fetch_assoc()) { while ($row1 = $simRes->fetch_assoc()) {
$pt = (object)[]; $pt = (object)[];
$pt->x = $row1["time"]*1000 + 30*60*1000; $pt->x = $row1["time"]*1000 + 30*60*1000;
$pt->y = $row1["Vorhersage"]; $pt->y = $row1["Vorhersage"];
$dataset->data[] = clone $pt; $dataset->data[] = clone $pt;
}*/ }*/
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
$rownext = $simRes->fetch_assoc(); $rownext = $simRes->fetch_assoc();
$nextSimTimestamp = $rownext["time"]*1000 + 30*60*1000; $nextSimTimestamp = $rownext["time"]*1000 + 30*60*1000;
} }
if ($result->num_rows > 1) { if ($result->num_rows > 1) {
$ii = 1; $ii = 1;
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."55"; $dataset->backgroundColor = $linecolors[$name]."55";
$dataset->borderWidth=1; $dataset->borderWidth=1;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
if ($name == "Solarleistung") { if ($name == "Solarleistung") {
$dataset->stack = "SolarPwr"; $dataset->stack = "SolarPwr";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} else if ($name == "Ladestand") { } else if ($name == "Ladestand") {
$dataset->stack = "Charge"; $dataset->stack = "Charge";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y1'; $dataset->yAxisID = 'y1';
} else { } else {
$dataset->stack = "Consumers"; $dataset->stack = "Consumers";
if ($filled == 0) { if ($filled == 0) {
$filled = 1; $filled = 1;
$dataset->fill = "origin"; $dataset->fill = "origin";
} else { } else {
$dataset->fill = "-1"; $dataset->fill = "-1";
} }
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} }
$dataset->label = $name; $dataset->label = $name;
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value * 1000; $obj->labels[] = $value * 1000;
} }
} }
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$ii = 1; $ii = 1;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} else { } else {
if(($value * 1000) < $nextSimTimestamp){ if(($value * 1000) < $nextSimTimestamp){
$obj->datasets[0]->data[] = $row1["Vorhersage"]; $obj->datasets[0]->data[] = $row1["Vorhersage"];
}else{ }else{
$row1 = $rownext; $row1 = $rownext;
$rownext = $simRes->fetch_assoc(); $rownext = $simRes->fetch_assoc();
$nextSimTimestamp = $rownext["time"]*1000 + 30*60*1000; $nextSimTimestamp = $rownext["time"]*1000 + 30*60*1000;
$obj->datasets[0]->data[] = $row1["Vorhersage"]; $obj->datasets[0]->data[] = $row1["Vorhersage"];
} }
$obj->labels[] = $value * 1000; $obj->labels[] = $value * 1000;
} }
} }
} }
} }
$obj->labels[] = $nextSimTimestamp; //Draw future forecast $obj->labels[] = $nextSimTimestamp; //Draw future forecast
$obj->datasets[0]->data[] = $rownext["Vorhersage"]; $obj->datasets[0]->data[] = $rownext["Vorhersage"];
while($rownext = $simRes->fetch_assoc()){ while($rownext = $simRes->fetch_assoc()){
$obj->labels[] = $rownext["time"]*1000 + 30*60*1000; $obj->labels[] = $rownext["time"]*1000 + 30*60*1000;
$obj->datasets[0]->data[] = $rownext["Vorhersage"]; $obj->datasets[0]->data[] = $rownext["Vorhersage"];
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';
?> ?>

View File

@ -1,98 +1,98 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$consQuery = "SELECT $consQuery = "SELECT
DATE_FORMAT(datetime,'%Y') AS 'time', 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(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0)- heaterPwr/12) Solarverbrauch,
SUM(heaterPwr/12) AS Heizstab, SUM(heaterPwr/12) AS Heizstab,
SUM(IF(battP > 0, battP/12,0)) AS Batteriebezug, SUM(IF(battP > 0, battP/12,0)) AS Batteriebezug,
SUM(gridPcons/12) AS Netzbezug SUM(gridPcons/12) AS Netzbezug
FROM EnergyFlow FROM EnergyFlow
WHERE DATE_FORMAT(datetime,'%Y') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 10 YEAR),'%Y') WHERE DATE_FORMAT(datetime,'%Y') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 10 YEAR),'%Y')
GROUP BY time GROUP BY time
ORDER BY datetime ; "; ORDER BY datetime ; ";
$linecolors["Solarverbrauch"] = "#FFFF00"; $linecolors["Solarverbrauch"] = "#FFFF00";
$linecolors["UG"] = "#FFaa00"; $linecolors["UG"] = "#FFaa00";
$linecolors["OG"] = "#FF4400"; $linecolors["OG"] = "#FF4400";
$linecolors["Auto UG"] = "#00aaFF"; $linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF"; $linecolors["Auto OG"] = "#0044FF";
$linecolors["Heizstab"] = "#FF6600"; $linecolors["Heizstab"] = "#FF6600";
$linecolors["Batteriebezug"] = "#00aa00"; $linecolors["Batteriebezug"] = "#00aa00";
$linecolors["Netzbezug"] = "#FF0000"; $linecolors["Netzbezug"] = "#FF0000";
$linecolors["Ladestand"] = "#00aa00"; $linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#2222FF"; $linecolors["Vorhersage"] = "#2222FF";
if (checkLogin()) { if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $consQuery); $result = mysqli_query($mysql, $consQuery);
if(!$result){ if(!$result){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
$obj = (object)[]; // Cast empty array to object $obj = (object)[]; // Cast empty array to object
$obj->labels = []; $obj->labels = [];
$obj->datasets = []; $obj->datasets = [];
$i = 0; $i = 0;
$filled = 0; $filled = 0;
if ($result->num_rows > 1) { if ($result->num_rows > 1) {
$ii = 0; $ii = 0;
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."55"; $dataset->backgroundColor = $linecolors[$name]."55";
$dataset->borderWidth=1; $dataset->borderWidth=1;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
if ($name == "Solarleistung") { if ($name == "Solarleistung") {
$dataset->stack = "SolarPwr"; $dataset->stack = "SolarPwr";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} else if ($name == "Ladestand") { } else if ($name == "Ladestand") {
$dataset->stack = "Charge"; $dataset->stack = "Charge";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y1'; $dataset->yAxisID = 'y1';
} else { } else {
$dataset->stack = "Consumers"; $dataset->stack = "Consumers";
if ($filled == 0) { if ($filled == 0) {
$filled = 1; $filled = 1;
$dataset->fill = "origin"; $dataset->fill = "origin";
} else { } else {
$dataset->fill = "-1"; $dataset->fill = "-1";
} }
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} }
$dataset->label = $name; $dataset->label = $name;
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$ii = 0; $ii = 0;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
} }
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';

View File

@ -1,98 +1,98 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$consQuery = "SELECT $consQuery = "SELECT
DATE_FORMAT(datetime, '%d.%b.') AS 'time', 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(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0)- heaterPwr/12) Solarverbrauch,
SUM(heaterPwr/12) AS Heizstab, SUM(heaterPwr/12) AS Heizstab,
SUM(IF(battP > 0, battP/12,0)) AS Batteriebezug, SUM(IF(battP > 0, battP/12,0)) AS Batteriebezug,
SUM(gridPcons/12) AS Netzbezug SUM(gridPcons/12) AS Netzbezug
FROM EnergyFlow FROM EnergyFlow
WHERE DATE_FORMAT(datetime,'%Y%m%d') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 1 MONTH),'%Y%m%d') 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.') GROUP BY DATE_FORMAT(datetime, '%d.%b.')
ORDER BY datetime ; "; ORDER BY datetime ; ";
$linecolors["Solarverbrauch"] = "#FFFF00"; $linecolors["Solarverbrauch"] = "#FFFF00";
$linecolors["UG"] = "#FFaa00"; $linecolors["UG"] = "#FFaa00";
$linecolors["OG"] = "#FF4400"; $linecolors["OG"] = "#FF4400";
$linecolors["Auto UG"] = "#00aaFF"; $linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF"; $linecolors["Auto OG"] = "#0044FF";
$linecolors["Heizstab"] = "#FF6600"; $linecolors["Heizstab"] = "#FF6600";
$linecolors["Batteriebezug"] = "#00aa00"; $linecolors["Batteriebezug"] = "#00aa00";
$linecolors["Netzbezug"] = "#FF0000"; $linecolors["Netzbezug"] = "#FF0000";
$linecolors["Ladestand"] = "#00aa00"; $linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#2222FF"; $linecolors["Vorhersage"] = "#2222FF";
if (checkLogin()) { if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $consQuery); $result = mysqli_query($mysql, $consQuery);
if(!$result){ if(!$result){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
$obj = (object)[]; // Cast empty array to object $obj = (object)[]; // Cast empty array to object
$obj->labels = []; $obj->labels = [];
$obj->datasets = []; $obj->datasets = [];
$i = 0; $i = 0;
$filled = 0; $filled = 0;
if ($result->num_rows > 1) { if ($result->num_rows > 1) {
$ii = 0; $ii = 0;
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."55"; $dataset->backgroundColor = $linecolors[$name]."55";
$dataset->borderWidth=1; $dataset->borderWidth=1;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
if ($name == "Solarleistung") { if ($name == "Solarleistung") {
$dataset->stack = "SolarPwr"; $dataset->stack = "SolarPwr";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} else if ($name == "Ladestand") { } else if ($name == "Ladestand") {
$dataset->stack = "Charge"; $dataset->stack = "Charge";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y1'; $dataset->yAxisID = 'y1';
} else { } else {
$dataset->stack = "Consumers"; $dataset->stack = "Consumers";
if ($filled == 0) { if ($filled == 0) {
$filled = 1; $filled = 1;
$dataset->fill = "origin"; $dataset->fill = "origin";
} else { } else {
$dataset->fill = "-1"; $dataset->fill = "-1";
} }
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} }
$dataset->label = $name; $dataset->label = $name;
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$ii = 0; $ii = 0;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
} }
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';

View File

@ -1,98 +1,98 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$consQuery = "SELECT $consQuery = "SELECT
DATE_FORMAT(datetime, '%b. %y') AS 'time', 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(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0)- heaterPwr/12) Solarverbrauch,
SUM(heaterPwr/12) AS Heizstab, SUM(heaterPwr/12) AS Heizstab,
SUM(IF(battP > 0, battP/12,0)) AS Batteriebezug, SUM(IF(battP > 0, battP/12,0)) AS Batteriebezug,
SUM(gridPcons/12) AS Netzbezug SUM(gridPcons/12) AS Netzbezug
FROM EnergyFlow FROM EnergyFlow
WHERE DATE_FORMAT(datetime,'%Y%m') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 13 MONTH),'%Y%m') WHERE DATE_FORMAT(datetime,'%Y%m') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 13 MONTH),'%Y%m')
GROUP BY DATE_FORMAT(datetime, '%b. %y') GROUP BY DATE_FORMAT(datetime, '%b. %y')
ORDER BY datetime ; "; ORDER BY datetime ; ";
$linecolors["Solarverbrauch"] = "#FFFF00"; $linecolors["Solarverbrauch"] = "#FFFF00";
$linecolors["UG"] = "#FFaa00"; $linecolors["UG"] = "#FFaa00";
$linecolors["OG"] = "#FF4400"; $linecolors["OG"] = "#FF4400";
$linecolors["Auto UG"] = "#00aaFF"; $linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF"; $linecolors["Auto OG"] = "#0044FF";
$linecolors["Heizstab"] = "#FF6600"; $linecolors["Heizstab"] = "#FF6600";
$linecolors["Batteriebezug"] = "#00aa00"; $linecolors["Batteriebezug"] = "#00aa00";
$linecolors["Netzbezug"] = "#FF0000"; $linecolors["Netzbezug"] = "#FF0000";
$linecolors["Ladestand"] = "#00aa00"; $linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#2222FF"; $linecolors["Vorhersage"] = "#2222FF";
if (checkLogin()) { if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $consQuery); $result = mysqli_query($mysql, $consQuery);
if(!$result){ if(!$result){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
$obj = (object)[]; // Cast empty array to object $obj = (object)[]; // Cast empty array to object
$obj->labels = []; $obj->labels = [];
$obj->datasets = []; $obj->datasets = [];
$i = 0; $i = 0;
$filled = 0; $filled = 0;
if ($result->num_rows > 1) { if ($result->num_rows > 1) {
$ii = 0; $ii = 0;
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."55"; $dataset->backgroundColor = $linecolors[$name]."55";
$dataset->borderWidth=1; $dataset->borderWidth=1;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
if ($name == "Solarleistung") { if ($name == "Solarleistung") {
$dataset->stack = "SolarPwr"; $dataset->stack = "SolarPwr";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} else if ($name == "Ladestand") { } else if ($name == "Ladestand") {
$dataset->stack = "Charge"; $dataset->stack = "Charge";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y1'; $dataset->yAxisID = 'y1';
} else { } else {
$dataset->stack = "Consumers"; $dataset->stack = "Consumers";
if ($filled == 0) { if ($filled == 0) {
$filled = 1; $filled = 1;
$dataset->fill = "origin"; $dataset->fill = "origin";
} else { } else {
$dataset->fill = "-1"; $dataset->fill = "-1";
} }
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} }
$dataset->label = $name; $dataset->label = $name;
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$ii = 0; $ii = 0;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
} }
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';

View File

@ -1,175 +1,175 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$consEstQuery = "SELECT $consEstQuery = "SELECT
UNIX_TIMESTAMP(DATE_ADD(datetime, INTERVAL 28 DAY)) AS 'time', UNIX_TIMESTAMP(DATE_ADD(datetime, INTERVAL 28 DAY)) AS 'time',
SUM(-(totalConsumption + heaterPwr)/48) AS 'Vorraussichtl. Verbrauch' SUM(-(totalConsumption + heaterPwr)/48) AS 'Vorraussichtl. Verbrauch'
FROM EnergyFlow FROM EnergyFlow
WHERE WHERE
DATE(datetime) >= DATE(DATE_SUB(NOW(),INTERVAL 28 DAY)) And DATE(datetime) != DATE(NOW()) DATE(datetime) >= DATE(DATE_SUB(NOW(),INTERVAL 28 DAY)) And DATE(datetime) != DATE(NOW())
GROUP BY WEEKDAY(datetime) GROUP BY WEEKDAY(datetime)
ORDER BY datetime"; ORDER BY datetime";
$prodEstQuery = "SELECT UNIX_TIMESTAMP(CONVERT_TZ(period_End,'GMT','Europe/Berlin')) AS 'time', $prodEstQuery = "SELECT UNIX_TIMESTAMP(CONVERT_TZ(period_End,'GMT','Europe/Berlin')) AS 'time',
SUM(power*500) AS 'Vorhersage' SUM(power*500) AS 'Vorhersage'
FROM simPower FROM simPower
WHERE DATE(CONVERT_TZ(period_End,'GMT','Europe/Berlin')) >= DATE(DATE_SUB(NOW(),INTERVAL 7 DAY)) WHERE DATE(CONVERT_TZ(period_End,'GMT','Europe/Berlin')) >= DATE(DATE_SUB(NOW(),INTERVAL 7 DAY))
GROUP BY DAY(CONVERT_TZ(period_End,'GMT','Europe/Berlin')) GROUP BY DAY(CONVERT_TZ(period_End,'GMT','Europe/Berlin'))
ORDER BY period_End;"; ORDER BY period_End;";
$prodRealQuery = "SELECT $prodRealQuery = "SELECT
UNIX_TIMESTAMP(datetime) AS 'time', UNIX_TIMESTAMP(datetime) AS 'time',
SUM(pvP/12) AS 'Tatsächliche Erzeugung', SUM(pvP/12) AS 'Tatsächliche Erzeugung',
SUM(-totalConsumption/12) AS 'Tatsächlicher Verbrauch' SUM(-totalConsumption/12) AS 'Tatsächlicher Verbrauch'
FROM EnergyFlow FROM EnergyFlow
WHERE WHERE
DATE(datetime) >= DATE(DATE_SUB(NOW(),INTERVAL 7 DAY)) DATE(datetime) >= DATE(DATE_SUB(NOW(),INTERVAL 7 DAY))
GROUP BY DAY(datetime) GROUP BY DAY(datetime)
ORDER BY datetime"; ORDER BY datetime";
$linecolors["Tatsächliche Erzeugung"] = "#cccc00"; $linecolors["Tatsächliche Erzeugung"] = "#cccc00";
$linecolors["Tatsächlicher Verbrauch"] = "#EE9900"; $linecolors["Tatsächlicher Verbrauch"] = "#EE9900";
$linecolors["Vorraussichtl. Verbrauch"] = "#BB4400"; $linecolors["Vorraussichtl. Verbrauch"] = "#BB4400";
$linecolors["Auto UG"] = "#00aaFF"; $linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF"; $linecolors["Auto OG"] = "#0044FF";
$linecolors["Heizstab"] = "#FF0000"; $linecolors["Heizstab"] = "#FF0000";
$linecolors["Batterieladung"] = "#00aa00"; $linecolors["Batterieladung"] = "#00aa00";
$linecolors["Einspeisung"] = "#b0b0b0"; $linecolors["Einspeisung"] = "#b0b0b0";
$linecolors["Ladestand"] = "#00aa00"; $linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#4444FF"; $linecolors["Vorhersage"] = "#4444FF";
if (checkLogin()) { if (checkLogin()) {
$mysql_server = "localhost:3310"; $mysql_server = "localhost:3310";
$mysql_user = "solarLog"; $mysql_user = "solarLog";
$mysql_pass = "iZ6_ZVul0!vE2.qJ0QSc"; $mysql_pass = "iZ6_ZVul0!vE2.qJ0QSc";
$mysql_db = "solarLog"; $mysql_db = "solarLog";
$mysql = new mysqli($mysql_server, $mysql_user, $mysql_pass, $mysql_db); $mysql = new mysqli($mysql_server, $mysql_user, $mysql_pass, $mysql_db);
$consEst = mysqli_query($mysql, $consEstQuery); $consEst = mysqli_query($mysql, $consEstQuery);
$prodEst = mysqli_query($mysql,$prodEstQuery); $prodEst = mysqli_query($mysql,$prodEstQuery);
$prodReal = mysqli_query($mysql,$prodRealQuery); $prodReal = mysqli_query($mysql,$prodRealQuery);
if(!$consEst){ if(!$consEst){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
if(!$prodEst){ if(!$prodEst){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
if(!$prodRealQuery){ if(!$prodRealQuery){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
$obj = (object)[]; // Cast empty array to object $obj = (object)[]; // Cast empty array to object
$obj->labels = []; $obj->labels = [];
$obj->datasets = []; $obj->datasets = [];
$i = 0; $i = 0;
$filled = 0; $filled = 0;
if($consEst->num_rows > 1){ if($consEst->num_rows > 1){
$row = $consEst->fetch_assoc(); $row = $consEst->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."66"; $dataset->backgroundColor = $linecolors[$name]."66";
$dataset->borderWidth=1; $dataset->borderWidth=1;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
$dataset->stack = $name; $dataset->stack = $name;
//$dataset->fill = "none"; //$dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
$dataset->label = $name; $dataset->label = $name;
for($i=0;$i<7;$i++){ for($i=0;$i<7;$i++){
$dataset->data[] = NULL; $dataset->data[] = NULL;
} }
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
} }
} }
while ($row = $consEst->fetch_assoc()) { while ($row = $consEst->fetch_assoc()) {
$ii = 0; $ii = 0;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} }
} }
} }
} }
if ($prodEst->num_rows > 1) { if ($prodEst->num_rows > 1) {
$row = $prodEst->fetch_assoc(); $row = $prodEst->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."55"; $dataset->backgroundColor = $linecolors[$name]."55";
$dataset->borderWidth=1; $dataset->borderWidth=1;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
$dataset->stack = $name; $dataset->stack = $name;
//$dataset->fill = "none"; //$dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
$dataset->label = $name; $dataset->label = $name;
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
} else { } else {
$obj->labels[] = $value * 1000; $obj->labels[] = $value * 1000;
} }
} }
while ($row = $prodEst->fetch_assoc()) { while ($row = $prodEst->fetch_assoc()) {
$ii = 1; $ii = 1;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value * 1000; $obj->labels[] = $value * 1000;
} }
} }
} }
} }
if($prodReal->num_rows > 1){ if($prodReal->num_rows > 1){
$row = $prodReal->fetch_assoc(); $row = $prodReal->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."55"; $dataset->backgroundColor = $linecolors[$name]."55";
$dataset->borderWidth=1; $dataset->borderWidth=1;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
$dataset->stack = $name; $dataset->stack = $name;
//$dataset->fill = "none"; //$dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
$dataset->label = $name; $dataset->label = $name;
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
} }
} }
while ($row = $prodReal->fetch_assoc()) { while ($row = $prodReal->fetch_assoc()) {
$ii = 2; $ii = 2;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} }
} }
} }
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';

View File

@ -1,105 +1,105 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$heatQuery = "SELECT $heatQuery = "SELECT
UNIX_TIMESTAMP(Heater.datetime) AS time, UNIX_TIMESTAMP(Heater.datetime) AS time,
PufferU AS 'Speicher unten', PufferU AS 'Speicher unten',
PufferM AS 'Speicher mitte', PufferM AS 'Speicher mitte',
PufferO AS 'Speicher oben', PufferO AS 'Speicher oben',
thermeVLfb AS 'Therme Vorlauf Fußboden', thermeVLfb AS 'Therme Vorlauf Fußboden',
thermeRL AS 'Therme Rücklauf', thermeRL AS 'Therme Rücklauf',
heaterVL AS 'Heizstab Vorlauf', heaterVL AS 'Heizstab Vorlauf',
heaterRL AS 'Heizstab Rücklauf', heaterRL AS 'Heizstab Rücklauf',
fbVL AS 'Fußboden Vorlauf', fbVL AS 'Fußboden Vorlauf',
fbRL AS 'Fußboden Rücklauf' fbRL AS 'Fußboden Rücklauf'
FROM Heater FROM Heater
WHERE Heater.datetime BETWEEN DATE_SUB(NOW(),INTERVAL 24 HOUR) and NOW() WHERE Heater.datetime BETWEEN DATE_SUB(NOW(),INTERVAL 24 HOUR) and NOW()
ORDER BY Heater.datetime"; ORDER BY Heater.datetime";
$waterQuery = "SELECT UNIX_TIMESTAMP(wasser.datetime) AS time, rate AS 'Wasserverbrauch' $waterQuery = "SELECT UNIX_TIMESTAMP(wasser.datetime) AS time, rate AS 'Wasserverbrauch'
FROM solarLog.wasser FROM solarLog.wasser
WHERE wasser.datetime BETWEEN DATE_SUB(NOW(),INTERVAL 24 HOUR) and NOW() WHERE wasser.datetime BETWEEN DATE_SUB(NOW(),INTERVAL 24 HOUR) and NOW()
ORDER BY wasser.datetime"; ORDER BY wasser.datetime";
$linecolors["Speicher oben"] = "#FF5500"; $linecolors["Speicher oben"] = "#FF5500";
$linecolors["Speicher mitte"] = "#FFaa00"; $linecolors["Speicher mitte"] = "#FFaa00";
$linecolors["Speicher unten"] = "#FFFF00"; $linecolors["Speicher unten"] = "#FFFF00";
$linecolors["Therme Vorlauf Fußboden"] = "#bb0000"; $linecolors["Therme Vorlauf Fußboden"] = "#bb0000";
$linecolors["Therme Rücklauf"] = "#ee0000"; $linecolors["Therme Rücklauf"] = "#ee0000";
$linecolors["Heizstab Vorlauf"] = "#9900bb"; $linecolors["Heizstab Vorlauf"] = "#9900bb";
$linecolors["Heizstab Rücklauf"] = "#8800aa"; $linecolors["Heizstab Rücklauf"] = "#8800aa";
$linecolors["Fußboden Vorlauf"] = "#00FF00"; $linecolors["Fußboden Vorlauf"] = "#00FF00";
$linecolors["Fußboden Rücklauf"] = "#00aa00"; $linecolors["Fußboden Rücklauf"] = "#00aa00";
$linecolors["Wasserverbrauch"] = "#2222FF"; $linecolors["Wasserverbrauch"] = "#2222FF";
if (checkLogin()) { if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $heatQuery); $result = mysqli_query($mysql, $heatQuery);
$simRes = mysqli_query($mysql,$waterQuery); $simRes = mysqli_query($mysql,$waterQuery);
if(!$result){ if(!$result){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
$obj = (object)[]; // Cast empty array to object $obj = (object)[]; // Cast empty array to object
$obj->labels = []; $obj->labels = [];
$obj->datasets = []; $obj->datasets = [];
$i = 0; $i = 0;
$filled = 0; $filled = 0;
if ($result->num_rows > 1) { if ($result->num_rows > 1) {
$ii = 0; $ii = 0;
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."22"; $dataset->backgroundColor = $linecolors[$name]."22";
$dataset->borderWidth=2; $dataset->borderWidth=2;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
if(strpos($name,"Speicher") === false) { if(strpos($name,"Speicher") === false) {
$dataset->fill = "none"; $dataset->fill = "none";
} else { } else {
// $dataset->stack = "Consumers"; // $dataset->stack = "Consumers";
if ($filled == 0) { if ($filled == 0) {
$filled = 1; $filled = 1;
$dataset->fill = "origin"; $dataset->fill = "origin";
} else { } else {
$dataset->fill = "-1"; $dataset->fill = "-1";
} }
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} }
$dataset->label = $name; $dataset->label = $name;
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value * 1000; $obj->labels[] = $value * 1000;
} }
} }
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$ii = 0; $ii = 0;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value * 1000; $obj->labels[] = $value * 1000;
} }
} }
} }
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';

View File

@ -1,165 +1,165 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
if(!isset($_GET["TO"])){ if(!isset($_GET["TO"])){
$_GET["TO"] = 12; $_GET["TO"] = 12;
} }
$_GET["TO"] = intval($_GET["TO"]); $_GET["TO"] = intval($_GET["TO"]);
if(!isset($_GET["FROM"])){ if(!isset($_GET["FROM"])){
$_GET["FROM"] = -24; $_GET["FROM"] = -24;
} }
$_GET["FROM"] = intval($_GET["FROM"]); $_GET["FROM"] = intval($_GET["FROM"]);
$consQuery = "SELECT $consQuery = "SELECT
UNIX_TIMESTAMP(EnergyFlow.datetime) AS time, UNIX_TIMESTAMP(EnergyFlow.datetime) AS time,
pvP AS Solarleistung, pvP AS Solarleistung,
IF(-totalConsumption - IF(gridP>0, gridP, 0) - IF(battP>0, battP, 0) > 0, -totalConsumption - IF(gridP>0, gridP, 0) - IF(battP>0, battP, 0), 0) AS Direktverbrauch, IF(-totalConsumption - IF(gridP>0, gridP, 0) - IF(battP>0, battP, 0) > 0, -totalConsumption - IF(gridP>0, gridP, 0) - IF(battP>0, battP, 0), 0) AS Direktverbrauch,
IF(battP>0, battP, 0) AS Batteriebezug, IF(battP>0, battP, 0) AS Batteriebezug,
gridPcons AS Netzbezug, gridPcons AS Netzbezug,
-totalConsumption AS Verbrauch,". -totalConsumption AS Verbrauch,".
//IF(battP<0, -battP, 0) AS Batterieladung, //IF(battP<0, -battP, 0) AS Batterieladung,
"soc AS Ladestand "soc AS Ladestand
FROM solarLog.EnergyFlow FROM solarLog.EnergyFlow
WHERE EnergyFlow.datetime BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"])." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR) WHERE EnergyFlow.datetime BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"])." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR)
ORDER BY EnergyFlow.datetime"; ORDER BY EnergyFlow.datetime";
$simQuery = "SELECT $simQuery = "SELECT
UNIX_TIMESTAMP(simPower.period_end) AS time, UNIX_TIMESTAMP(simPower.period_end) AS time,
power*1000 AS 'Vorhersage' power*1000 AS 'Vorhersage'
FROM solarLog.simPower FROM solarLog.simPower
WHERE simPower.period_end BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"])." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR) WHERE simPower.period_end BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"])." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR)
ORDER BY simPower.period_end"; ORDER BY simPower.period_end";
$linecolors["Solarleistung"] = "#FFFF00"; $linecolors["Solarleistung"] = "#FFFF00";
$linecolors["Direktverbrauch"] = "#FFcc00"; $linecolors["Direktverbrauch"] = "#FFcc00";
$linecolors["Verbrauch"] = "#FFaa44"; $linecolors["Verbrauch"] = "#FFaa44";
$linecolors["Auto UG"] = "#00aaFF"; $linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF"; $linecolors["Auto OG"] = "#0044FF";
$linecolors["Netzbezug"] = "#FF0000"; $linecolors["Netzbezug"] = "#FF0000";
$linecolors["Batteriebezug"] = "#00aa00"; $linecolors["Batteriebezug"] = "#00aa00";
$linecolors["Batterieladung"] = "#0033aa"; $linecolors["Batterieladung"] = "#0033aa";
$linecolors["Einspeisung"] = "#b0b0b0"; $linecolors["Einspeisung"] = "#b0b0b0";
$linecolors["Ladestand"] = "#00aa00"; $linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#2222FF"; $linecolors["Vorhersage"] = "#2222FF";
if (checkLogin()) { if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $consQuery); $result = mysqli_query($mysql, $consQuery);
$simRes = mysqli_query($mysql,$simQuery); $simRes = mysqli_query($mysql,$simQuery);
if(!$result){ if(!$result){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
$obj = (object)[]; // Cast empty array to object $obj = (object)[]; // Cast empty array to object
$obj->labels = []; $obj->labels = [];
$obj->datasets = []; $obj->datasets = [];
$i = 0; $i = 0;
$filled = 0; $filled = 0;
if ($simRes->num_rows > 1) { if ($simRes->num_rows > 1) {
$dataset = (object)[]; $dataset = (object)[];
$row1 = $simRes->fetch_assoc(); $row1 = $simRes->fetch_assoc();
$dataset->borderColor = $linecolors["Vorhersage"]; $dataset->borderColor = $linecolors["Vorhersage"];
$dataset->backgroundColor = $linecolors["Vorhersage"]."55"; $dataset->backgroundColor = $linecolors["Vorhersage"]."55";
$dataset->borderWidth=1.5; $dataset->borderWidth=1.5;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
$dataset->stack = "sim"; $dataset->stack = "sim";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
$dataset->label = "Vorhersage"; $dataset->label = "Vorhersage";
/*$pt = (object)[]; /*$pt = (object)[];
$pt->x = $row["time"]*1000; $pt->x = $row["time"]*1000;
$pt->y = $row["Vorhersage"]; $pt->y = $row["Vorhersage"];
$dataset->data[] = clone $pt; $dataset->data[] = clone $pt;
while ($row = $simRes->fetch_assoc()) { while ($row = $simRes->fetch_assoc()) {
$pt = (object)[]; $pt = (object)[];
$pt->x = $row["time"]*1000 + 30*60*1000; $pt->x = $row["time"]*1000 + 30*60*1000;
$pt->y = $row["Vorhersage"]; $pt->y = $row["Vorhersage"];
$dataset->data[] = clone $pt; $dataset->data[] = clone $pt;
}*/ }*/
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
$rownext = $simRes->fetch_assoc(); $rownext = $simRes->fetch_assoc();
$nextSimTimestamp = $rownext["time"]*1000 + 30*60*1000; $nextSimTimestamp = $rownext["time"]*1000 + 30*60*1000;
} }
if ($result->num_rows > 1) { if ($result->num_rows > 1) {
$ii = 1; $ii = 1;
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."22"; $dataset->backgroundColor = $linecolors[$name]."22";
$dataset->borderWidth=1; $dataset->borderWidth=1;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
if ($name == "Solarleistung") { if ($name == "Solarleistung") {
$dataset->stack = "SolarPwr"; $dataset->stack = "SolarPwr";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
}else if ($name == "Verbrauch") { }else if ($name == "Verbrauch") {
$dataset->stack = "ConsPwr"; $dataset->stack = "ConsPwr";
$dataset->fill = "1"; $dataset->fill = "1";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
}else if ($name == "Batterieladung") { }else if ($name == "Batterieladung") {
$dataset->stack = "ConsPwr"; $dataset->stack = "ConsPwr";
$dataset->fill = "-1"; $dataset->fill = "-1";
$dataset->backgroundColor = $linecolors[$name]."77"; $dataset->backgroundColor = $linecolors[$name]."77";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} else if ($name == "Ladestand") { } else if ($name == "Ladestand") {
$dataset->stack = "Charge"; $dataset->stack = "Charge";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y1'; $dataset->yAxisID = 'y1';
} else { } else {
$dataset->stack = "Consumers"; $dataset->stack = "Consumers";
if ($filled == 0) { if ($filled == 0) {
$filled = 1; $filled = 1;
$dataset->fill = "origin"; $dataset->fill = "origin";
} else { } else {
$dataset->fill = "-1"; $dataset->fill = "-1";
} }
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} }
$dataset->label = $name; $dataset->label = $name;
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value * 1000; $obj->labels[] = $value * 1000;
} }
} }
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$ii = 1; $ii = 1;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} else { } else {
if(($value * 1000) < $nextSimTimestamp){ if(($value * 1000) < $nextSimTimestamp){
$obj->datasets[0]->data[] = $row1["Vorhersage"]; $obj->datasets[0]->data[] = $row1["Vorhersage"];
}else{ }else{
$row1 = $rownext; $row1 = $rownext;
$rownext = $simRes->fetch_assoc(); $rownext = $simRes->fetch_assoc();
$nextSimTimestamp = $rownext["time"]*1000 + 30*60*1000; $nextSimTimestamp = $rownext["time"]*1000 + 30*60*1000;
$obj->datasets[0]->data[] = $row1["Vorhersage"]; $obj->datasets[0]->data[] = $row1["Vorhersage"];
} }
$obj->labels[] = $value * 1000; $obj->labels[] = $value * 1000;
} }
} }
} }
} }
$obj->labels[] = $nextSimTimestamp; //Draw future forecast $obj->labels[] = $nextSimTimestamp; //Draw future forecast
$obj->datasets[0]->data[] = $rownext["Vorhersage"]; $obj->datasets[0]->data[] = $rownext["Vorhersage"];
while($rownext = $simRes->fetch_assoc()){ while($rownext = $simRes->fetch_assoc()){
$obj->labels[] = $rownext["time"]*1000 + 30*60*1000; $obj->labels[] = $rownext["time"]*1000 + 30*60*1000;
$obj->datasets[0]->data[] = $rownext["Vorhersage"]; $obj->datasets[0]->data[] = $rownext["Vorhersage"];
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';
?> ?>

View File

@ -1,98 +1,98 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$consQuery = "SELECT $consQuery = "SELECT
DATE_FORMAT(datetime,'%Y') AS 'time', 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(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0) - heaterPwr/12) Direktverbrauch,
SUM(heaterPwr/12) AS Heizstab, SUM(heaterPwr/12) AS Heizstab,
SUM(IF(battP < 0, -battP/12,0)) AS Batterieladung, SUM(IF(battP < 0, -battP/12,0)) AS Batterieladung,
SUM(gridPfeed/12) AS Einspeisung SUM(gridPfeed/12) AS Einspeisung
FROM EnergyFlow FROM EnergyFlow
WHERE DATE_FORMAT(datetime,'%Y') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 10 YEAR),'%Y') WHERE DATE_FORMAT(datetime,'%Y') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 10 YEAR),'%Y')
GROUP BY DATE_FORMAT(datetime, '%Y') GROUP BY DATE_FORMAT(datetime, '%Y')
ORDER BY datetime ; "; ORDER BY datetime ; ";
$linecolors["Direktverbrauch"] = "#FFFF00"; $linecolors["Direktverbrauch"] = "#FFFF00";
$linecolors["UG"] = "#FFaa00"; $linecolors["UG"] = "#FFaa00";
$linecolors["OG"] = "#FF4400"; $linecolors["OG"] = "#FF4400";
$linecolors["Auto UG"] = "#00aaFF"; $linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF"; $linecolors["Auto OG"] = "#0044FF";
$linecolors["Heizstab"] = "#FF6600"; $linecolors["Heizstab"] = "#FF6600";
$linecolors["Batterieladung"] = "#00aa00"; $linecolors["Batterieladung"] = "#00aa00";
$linecolors["Einspeisung"] = "#FF0000"; $linecolors["Einspeisung"] = "#FF0000";
$linecolors["Ladestand"] = "#00aa00"; $linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#2222FF"; $linecolors["Vorhersage"] = "#2222FF";
if (checkLogin()) { if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $consQuery); $result = mysqli_query($mysql, $consQuery);
if(!$result){ if(!$result){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
$obj = (object)[]; // Cast empty array to object $obj = (object)[]; // Cast empty array to object
$obj->labels = []; $obj->labels = [];
$obj->datasets = []; $obj->datasets = [];
$i = 0; $i = 0;
$filled = 0; $filled = 0;
if ($result->num_rows > 1) { if ($result->num_rows > 1) {
$ii = 0; $ii = 0;
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."55"; $dataset->backgroundColor = $linecolors[$name]."55";
$dataset->borderWidth=1; $dataset->borderWidth=1;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
if ($name == "Solarleistung") { if ($name == "Solarleistung") {
$dataset->stack = "SolarPwr"; $dataset->stack = "SolarPwr";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} else if ($name == "Ladestand") { } else if ($name == "Ladestand") {
$dataset->stack = "Charge"; $dataset->stack = "Charge";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y1'; $dataset->yAxisID = 'y1';
} else { } else {
$dataset->stack = "Consumers"; $dataset->stack = "Consumers";
if ($filled == 0) { if ($filled == 0) {
$filled = 1; $filled = 1;
$dataset->fill = "origin"; $dataset->fill = "origin";
} else { } else {
$dataset->fill = "-1"; $dataset->fill = "-1";
} }
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} }
$dataset->label = $name; $dataset->label = $name;
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$ii = 0; $ii = 0;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
} }
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';

View File

@ -1,98 +1,98 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$consQuery = "SELECT $consQuery = "SELECT
DATE_FORMAT(datetime, '%d.%b.') AS 'time', 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(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0) - heaterPwr/12) Direktverbrauch,
SUM(heaterPwr/12) AS Heizstab, SUM(heaterPwr/12) AS Heizstab,
SUM(IF(battP < 0, -battP/12,0)) AS Batterieladung, SUM(IF(battP < 0, -battP/12,0)) AS Batterieladung,
SUM(gridPfeed/12) AS Einspeisung SUM(gridPfeed/12) AS Einspeisung
FROM EnergyFlow FROM EnergyFlow
WHERE DATE_FORMAT(datetime,'%Y%m%d') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 1 MONTH),'%Y%m%d') 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.') GROUP BY DATE_FORMAT(datetime, '%d.%b.')
ORDER BY datetime ; "; ORDER BY datetime ; ";
$linecolors["Direktverbrauch"] = "#FFFF00"; $linecolors["Direktverbrauch"] = "#FFFF00";
$linecolors["UG"] = "#FFaa00"; $linecolors["UG"] = "#FFaa00";
$linecolors["OG"] = "#FF4400"; $linecolors["OG"] = "#FF4400";
$linecolors["Auto UG"] = "#00aaFF"; $linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF"; $linecolors["Auto OG"] = "#0044FF";
$linecolors["Heizstab"] = "#FF6600"; $linecolors["Heizstab"] = "#FF6600";
$linecolors["Batterieladung"] = "#00aa00"; $linecolors["Batterieladung"] = "#00aa00";
$linecolors["Einspeisung"] = "#FF0000"; $linecolors["Einspeisung"] = "#FF0000";
$linecolors["Ladestand"] = "#00aa00"; $linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#2222FF"; $linecolors["Vorhersage"] = "#2222FF";
if (checkLogin()) { if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $consQuery); $result = mysqli_query($mysql, $consQuery);
if(!$result){ if(!$result){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
$obj = (object)[]; // Cast empty array to object $obj = (object)[]; // Cast empty array to object
$obj->labels = []; $obj->labels = [];
$obj->datasets = []; $obj->datasets = [];
$i = 0; $i = 0;
$filled = 0; $filled = 0;
if ($result->num_rows > 1) { if ($result->num_rows > 1) {
$ii = 0; $ii = 0;
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."55"; $dataset->backgroundColor = $linecolors[$name]."55";
$dataset->borderWidth=1; $dataset->borderWidth=1;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
if ($name == "Solarleistung") { if ($name == "Solarleistung") {
$dataset->stack = "SolarPwr"; $dataset->stack = "SolarPwr";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} else if ($name == "Ladestand") { } else if ($name == "Ladestand") {
$dataset->stack = "Charge"; $dataset->stack = "Charge";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y1'; $dataset->yAxisID = 'y1';
} else { } else {
$dataset->stack = "Consumers"; $dataset->stack = "Consumers";
if ($filled == 0) { if ($filled == 0) {
$filled = 1; $filled = 1;
$dataset->fill = "origin"; $dataset->fill = "origin";
} else { } else {
$dataset->fill = "-1"; $dataset->fill = "-1";
} }
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} }
$dataset->label = $name; $dataset->label = $name;
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$ii = 0; $ii = 0;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
} }
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';

View File

@ -1,98 +1,98 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$consQuery = "SELECT $consQuery = "SELECT
DATE_FORMAT(datetime,'%b. %y') AS 'time', 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(pvP/12 - IF(gridP < 0, -gridP/12,0) - IF(battP < 0, -battP/12,0) - heaterPwr/12) Direktverbrauch,
SUM(heaterPwr/12) AS Heizstab, SUM(heaterPwr/12) AS Heizstab,
SUM(IF(battP < 0, -battP/12,0)) AS Batterieladung, SUM(IF(battP < 0, -battP/12,0)) AS Batterieladung,
SUM(gridPfeed/12) AS Einspeisung SUM(gridPfeed/12) AS Einspeisung
FROM EnergyFlow FROM EnergyFlow
WHERE DATE_FORMAT(datetime,'%Y%m') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 13 MONTH),'%Y%m') WHERE DATE_FORMAT(datetime,'%Y%m') >= DATE_FORMAT(DATE_SUB(now(),INTERVAL 13 MONTH),'%Y%m')
GROUP BY DATE_FORMAT(datetime, '%b. %y') GROUP BY DATE_FORMAT(datetime, '%b. %y')
ORDER BY datetime ; "; ORDER BY datetime ; ";
$linecolors["Direktverbrauch"] = "#FFFF00"; $linecolors["Direktverbrauch"] = "#FFFF00";
$linecolors["UG"] = "#FFaa00"; $linecolors["UG"] = "#FFaa00";
$linecolors["OG"] = "#FF4400"; $linecolors["OG"] = "#FF4400";
$linecolors["Auto UG"] = "#00aaFF"; $linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF"; $linecolors["Auto OG"] = "#0044FF";
$linecolors["Heizstab"] = "#FF6600"; $linecolors["Heizstab"] = "#FF6600";
$linecolors["Batterieladung"] = "#00aa00"; $linecolors["Batterieladung"] = "#00aa00";
$linecolors["Einspeisung"] = "#FF0000"; $linecolors["Einspeisung"] = "#FF0000";
$linecolors["Ladestand"] = "#00aa00"; $linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#2222FF"; $linecolors["Vorhersage"] = "#2222FF";
if (checkLogin()) { if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $consQuery); $result = mysqli_query($mysql, $consQuery);
if(!$result){ if(!$result){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
$obj = (object)[]; // Cast empty array to object $obj = (object)[]; // Cast empty array to object
$obj->labels = []; $obj->labels = [];
$obj->datasets = []; $obj->datasets = [];
$i = 0; $i = 0;
$filled = 0; $filled = 0;
if ($result->num_rows > 1) { if ($result->num_rows > 1) {
$ii = 0; $ii = 0;
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
$dataset = (object)[]; $dataset = (object)[];
if ($name != "time") { if ($name != "time") {
$dataset->borderColor = $linecolors[$name]; $dataset->borderColor = $linecolors[$name];
$dataset->backgroundColor = $linecolors[$name]."55"; $dataset->backgroundColor = $linecolors[$name]."55";
$dataset->borderWidth=1; $dataset->borderWidth=1;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
if ($name == "Solarleistung") { if ($name == "Solarleistung") {
$dataset->stack = "SolarPwr"; $dataset->stack = "SolarPwr";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} else if ($name == "Ladestand") { } else if ($name == "Ladestand") {
$dataset->stack = "Charge"; $dataset->stack = "Charge";
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y1'; $dataset->yAxisID = 'y1';
} else { } else {
$dataset->stack = "Consumers"; $dataset->stack = "Consumers";
if ($filled == 0) { if ($filled == 0) {
$filled = 1; $filled = 1;
$dataset->fill = "origin"; $dataset->fill = "origin";
} else { } else {
$dataset->fill = "-1"; $dataset->fill = "-1";
} }
$dataset->yAxisID = 'y'; $dataset->yAxisID = 'y';
} }
$dataset->label = $name; $dataset->label = $name;
$dataset->data[] = $value; $dataset->data[] = $value;
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$ii = 0; $ii = 0;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if ($name != "time") { if ($name != "time") {
$obj->datasets[$ii]->data[] = $value; $obj->datasets[$ii]->data[] = $value;
$ii++; $ii++;
} else { } else {
$obj->labels[] = $value; $obj->labels[] = $value;
} }
} }
} }
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';

View File

@ -1,155 +1,155 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
if(!isset($_GET["year"])){ if(!isset($_GET["year"])){
$_GET["year"] = date("Y"); $_GET["year"] = date("Y");
}else{ }else{
$_GET["year"] = intval($_GET["year"]); $_GET["year"] = intval($_GET["year"]);
} }
if($_GET["year"] < 2018 || $_GET["year"] > date("Y")){ if($_GET["year"] < 2018 || $_GET["year"] > date("Y")){
exit; exit;
} }
if(isset($_GET["type"])){ if(isset($_GET["type"])){
if(strtolower($_GET["type"]) =="lastyear"){ if(strtolower($_GET["type"]) =="lastyear"){
$_GET["year"] = date("Y")-1; $_GET["year"] = date("Y")-1;
}elseif(strtolower($_GET["type"]) =="prelastyear"){ }elseif(strtolower($_GET["type"]) =="prelastyear"){
$_GET["year"] = date("Y")-2; $_GET["year"] = date("Y")-2;
} }
} }
$Query = "SELECT $Query = "SELECT
SUM(gridPcons/12000) as 'Stromverbrauch', SUM(gridPcons/12000) as 'Stromverbrauch',
SUM((gridPcons*cost)/12000)+140 as 'Stromkosten (140€ fix)', SUM((gridPcons*cost)/12000)+140 as 'Stromkosten (140€ fix)',
SUM(pvP - IF(gridP < 0, -gridP,0) - IF(battP < 0, -battP,0)- heaterPwr + IF(battP > 0, battP,0))*cost/12000 as 'Verbrauchsersparnis', SUM(pvP - IF(gridP < 0, -gridP,0) - IF(battP < 0, -battP,0)- heaterPwr + IF(battP > 0, battP,0))*cost/12000 as 'Verbrauchsersparnis',
SUM((gridPfeed*gain)/12000) as 'Einspeisevergütung', SUM((gridPfeed*gain)/12000) as 'Einspeisevergütung',
SUM(IF(gridP < 500, heaterPwr, 0)*0.063/12000) as 'Ersparnis Heizung', SUM(IF(gridP < 500, heaterPwr, 0)*0.063/12000) as 'Ersparnis Heizung',
SUM(IF(battP > 0, battP, 0)*cost/12000) as 'Ersparnis Batterie', SUM(IF(battP > 0, battP, 0)*cost/12000) as 'Ersparnis Batterie',
AVG(autonomy) AS 'Ø Autarkie', AVG(autonomy) AS 'Ø Autarkie',
(SUM(PL1_EV+PL2_EV+PL3_EV))/12 AS 'Autoladung ges. EG', (SUM(PL1_EV+PL2_EV+PL3_EV))/12 AS 'Autoladung ges. EG',
(((SUM(IF(gridP>100,0,PL1_EV+PL2_EV+PL3_EV)))/(SUM(PL1_EV+PL2_EV+PL3_EV))))*100 AS 'Autoladung Solar EG', (((SUM(IF(gridP>100,0,PL1_EV+PL2_EV+PL3_EV)))/(SUM(PL1_EV+PL2_EV+PL3_EV))))*100 AS 'Autoladung Solar EG',
(SUM(IF(gridP>100,0,(PL1_EV+PL2_EV+PL3_EV)*cost))/12) AS 'Ersparnis Solarladung EG', (SUM(IF(gridP>100,0,(PL1_EV+PL2_EV+PL3_EV)*cost))/12) AS 'Ersparnis Solarladung EG',
(SUM(PL1_EV+PL2_EV+PL3_EV))/24.5 AS 'Benzin gespart EG', (SUM(PL1_EV+PL2_EV+PL3_EV))/24.5 AS 'Benzin gespart EG',
(SUM(PL1_EVog+PL2_EVog+PL3_EVog))/12 AS 'Autoladung ges. OG', (SUM(PL1_EVog+PL2_EVog+PL3_EVog))/12 AS 'Autoladung ges. OG',
(((SUM(IF(gridP>100,0,PL1_EVog+PL2_EVog+PL3_EVog)))/(SUM(PL1_EVog+PL2_EVog+PL3_EVog))))*100 AS 'Autoladung Solar OG', (((SUM(IF(gridP>100,0,PL1_EVog+PL2_EVog+PL3_EVog)))/(SUM(PL1_EVog+PL2_EVog+PL3_EVog))))*100 AS 'Autoladung Solar OG',
(SUM(IF(gridP>100,0,(PL1_EVog+PL2_EVog+PL3_EVog)*cost))/12) AS 'Ersparnis Solarladung OG', (SUM(IF(gridP>100,0,(PL1_EVog+PL2_EVog+PL3_EVog)*cost))/12) AS 'Ersparnis Solarladung OG',
(SUM(PL1_EVog+PL2_EVog+PL3_EVog))/24.5 AS 'Benzin gespart OG' (SUM(PL1_EVog+PL2_EVog+PL3_EVog))/24.5 AS 'Benzin gespart OG'
FROM EnergyFlow JOIN gridCosts ON DATE(datetime) >= DATE(gridCosts.active_date) AND DATE(datetime) <= DATE(gridCosts.end_date) FROM EnergyFlow JOIN gridCosts ON DATE(datetime) >= DATE(gridCosts.active_date) AND DATE(datetime) <= DATE(gridCosts.end_date)
WHERE year(datetime) = ".$_GET["year"].";"; WHERE year(datetime) = ".$_GET["year"].";";
$PrevQuery = "SELECT $PrevQuery = "SELECT
SUM(gridPcons/12000) as 'Stromverbrauch', SUM(gridPcons/12000) as 'Stromverbrauch',
SUM((gridPcons*cost)/12000)+140 as 'Stromkosten (140€ fix)', SUM((gridPcons*cost)/12000)+140 as 'Stromkosten (140€ fix)',
SUM(pvP - IF(gridP < 0, -gridP,0) - IF(battP < 0, -battP,0)- heaterPwr + IF(battP > 0, battP,0))*cost/12000 as 'Verbrauchsersparnis', SUM(pvP - IF(gridP < 0, -gridP,0) - IF(battP < 0, -battP,0)- heaterPwr + IF(battP > 0, battP,0))*cost/12000 as 'Verbrauchsersparnis',
SUM((gridPfeed*gain)/12000) as 'Einspeisevergütung', SUM((gridPfeed*gain)/12000) as 'Einspeisevergütung',
SUM(IF(gridP < 500, heaterPwr, 0)*0.063/12000) as 'Ersparnis Heizung', SUM(IF(gridP < 500, heaterPwr, 0)*0.063/12000) as 'Ersparnis Heizung',
SUM(IF(battP > 0, battP, 0)*cost/12000) as 'Ersparnis Batterie', SUM(IF(battP > 0, battP, 0)*cost/12000) as 'Ersparnis Batterie',
AVG(autonomy) AS 'Ø Autarkie', AVG(autonomy) AS 'Ø Autarkie',
(SUM(PL1_EV+PL2_EV+PL3_EV))/12 AS 'Autoladung ges. EG', (SUM(PL1_EV+PL2_EV+PL3_EV))/12 AS 'Autoladung ges. EG',
(((SUM(IF(gridP>100,0,PL1_EV+PL2_EV+PL3_EV)))/(SUM(PL1_EV+PL2_EV+PL3_EV))))*100 AS 'Autoladung Solar EG', (((SUM(IF(gridP>100,0,PL1_EV+PL2_EV+PL3_EV)))/(SUM(PL1_EV+PL2_EV+PL3_EV))))*100 AS 'Autoladung Solar EG',
(SUM(IF(gridP>100,0,(PL1_EV+PL2_EV+PL3_EV)*cost))/12) AS 'Ersparnis Solarladung EG', (SUM(IF(gridP>100,0,(PL1_EV+PL2_EV+PL3_EV)*cost))/12) AS 'Ersparnis Solarladung EG',
(SUM(PL1_EV+PL2_EV+PL3_EV))/24.5 AS 'Benzin gespart EG', (SUM(PL1_EV+PL2_EV+PL3_EV))/24.5 AS 'Benzin gespart EG',
(SUM(PL1_EVog+PL2_EVog+PL3_EVog))/12 AS 'Autoladung ges. OG', (SUM(PL1_EVog+PL2_EVog+PL3_EVog))/12 AS 'Autoladung ges. OG',
(((SUM(IF(gridP>100,0,PL1_EVog+PL2_EVog+PL3_EVog)))/(SUM(PL1_EVog+PL2_EVog+PL3_EVog))))*100 AS 'Autoladung Solar OG', (((SUM(IF(gridP>100,0,PL1_EVog+PL2_EVog+PL3_EVog)))/(SUM(PL1_EVog+PL2_EVog+PL3_EVog))))*100 AS 'Autoladung Solar OG',
(SUM(IF(gridP>100,0,(PL1_EVog+PL2_EVog+PL3_EVog)*cost))/12) AS 'Ersparnis Solarladung OG', (SUM(IF(gridP>100,0,(PL1_EVog+PL2_EVog+PL3_EVog)*cost))/12) AS 'Ersparnis Solarladung OG',
(SUM(PL1_EVog+PL2_EVog+PL3_EVog))/24.5 AS 'Benzin gespart OG' (SUM(PL1_EVog+PL2_EVog+PL3_EVog))/24.5 AS 'Benzin gespart OG'
FROM EnergyFlow JOIN gridCosts ON DATE(datetime) >= DATE(gridCosts.active_date) AND DATE(datetime) <= DATE(gridCosts.end_date) FROM EnergyFlow JOIN gridCosts ON DATE(datetime) >= DATE(gridCosts.active_date) AND DATE(datetime) <= DATE(gridCosts.end_date)
WHERE year(datetime) = ".($_GET["year"]-1).";"; WHERE year(datetime) = ".($_GET["year"]-1).";";
$units = Array("kWh","","","","","","","%","kWh","%","","L","kWh","%","","L"); $units = Array("kWh","","","","","","","%","kWh","%","","L","kWh","%","","L");
$LessIsBetter = Array(true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false); $LessIsBetter = Array(true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false);
function array_insert($array,$values,$offset) { function array_insert($array,$values,$offset) {
return array_slice($array, 0, $offset, true) + $values + array_slice($array, $offset, NULL, true); return array_slice($array, 0, $offset, true) + $values + array_slice($array, $offset, NULL, true);
} }
if (checkLogin()) { if (checkLogin()) {
$html = "<div class='row row-info'>"; $html = "<div class='row row-info'>";
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$Res = mysqli_query($mysql,$Query); $Res = mysqli_query($mysql,$Query);
$ResPrev = mysqli_query($mysql,$PrevQuery); $ResPrev = mysqli_query($mysql,$PrevQuery);
if(!$Res || !$ResPrev){ if(!$Res || !$ResPrev){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
if ($Res->num_rows > 0) { if ($Res->num_rows > 0) {
$i = 0; $i = 0;
$row = $Res->fetch_assoc(); $row = $Res->fetch_assoc();
$rowPrev = $ResPrev->fetch_assoc(); $rowPrev = $ResPrev->fetch_assoc();
//$row["Vergütung+Einsparung Strom"] = $row["Einspeisevergütung"]+$row["Verbrauchsersparnis"]; //$row["Vergütung+Einsparung Strom"] = $row["Einspeisevergütung"]+$row["Verbrauchsersparnis"];
$row = array_insert($row,["Verg.+Einsp. Strom" => $row["Einspeisevergütung"]+$row["Verbrauchsersparnis"]],4); $row = array_insert($row,["Verg.+Einsp. Strom" => $row["Einspeisevergütung"]+$row["Verbrauchsersparnis"]],4);
$rowPrev = array_insert($rowPrev,["Verg.+Einsp. Strom" => $rowPrev["Einspeisevergütung"]+$rowPrev["Verbrauchsersparnis"]],4); $rowPrev = array_insert($rowPrev,["Verg.+Einsp. Strom" => $rowPrev["Einspeisevergütung"]+$rowPrev["Verbrauchsersparnis"]],4);
$i = 0; $i = 0;
foreach ($row as $name => $value) { foreach ($row as $name => $value) {
if(str_starts_with($name,"Autoladung ges.")){ if(str_starts_with($name,"Autoladung ges.")){
$html .= "</div><hr class='mt-2 mb-3 border-light' />"; $html .= "</div><hr class='mt-2 mb-3 border-light' />";
$html .= "<div class='row row-info'>"; $html .= "<div class='row row-info'>";
} }
/*$html .= "<div class='col-12 col-sm-4 col-md-2 col-xl-1'> /*$html .= "<div class='col-12 col-sm-4 col-md-2 col-xl-1'>
<div class='info-box'> <div class='info-box'>
<div class='info-box-content'> <div class='info-box-content'>
<span class='info-box-text'>".$name."</span> <span class='info-box-text'>".$name."</span>
<span class='info-box-number'>". <span class='info-box-number'>".
number_format(floatval($value),2,",",".") number_format(floatval($value),2,",",".")
."<small>".$units[$i++]."</small> ."<small>".$units[$i++]."</small>
</span> </span>
</div> </div>
<!-- /.info-box-content --> <!-- /.info-box-content -->
</div> </div>
</div>";*/ </div>";*/
$html .= "<div class='col'> $html .= "<div class='col'>
<div class='card stats border-0'> <div class='card stats border-0'>
<div class='card-body bg-dark bg-gradient rounded-top pb-1 pt-1'> <div class='card-body bg-dark bg-gradient rounded-top pb-1 pt-1'>
".$name." ".$name."
</div> </div>
<div class='card-footer text-center'>"; <div class='card-footer text-center'>";
if($_GET["year"] != date("Y")){ if($_GET["year"] != date("Y")){
if($LessIsBetter[$i]){ if($LessIsBetter[$i]){
if($value == 0) if($value == 0)
$dev=100; $dev=100;
else else
$dev = $rowPrev[$name]/$value; $dev = $rowPrev[$name]/$value;
//$first = round($rowPrev[$name]*10/$rowPrev[$name]); //allow for 10% deviation for displaying no tendency //$first = round($rowPrev[$name]*10/$rowPrev[$name]); //allow for 10% deviation for displaying no tendency
//$second = round($value); //allow for 10% deviation for displaying no tendency //$second = round($value); //allow for 10% deviation for displaying no tendency
$arrowGood = "down"; $arrowGood = "down";
$arrowBad = "up"; $arrowBad = "up";
}else{ }else{
if($rowPrev[$name] == 0) if($rowPrev[$name] == 0)
$dev=100; $dev=100;
else else
$dev = $value/$rowPrev[$name]; $dev = $value/$rowPrev[$name];
//$first = round($value); //allow for 10% deviation for displaying no tendency //$first = round($value); //allow for 10% deviation for displaying no tendency
//$second = round($rowPrev[$name]); //allow for 10% deviation for displaying no tendency //$second = round($rowPrev[$name]); //allow for 10% deviation for displaying no tendency
$arrowGood = "up"; $arrowGood = "up";
$arrowBad = "down"; $arrowBad = "down";
} }
if($dev > 1.05){ if($dev > 1.05){
$html .= "<span class='float-right text-success-emphasis'> $html .= "<span class='float-right text-success-emphasis'>
<i class='bi bi-arrow-".$arrowGood."' style='font-size: 0.9em;'></i> "; <i class='bi bi-arrow-".$arrowGood."' style='font-size: 0.9em;'></i> ";
}elseif($dev < 0.95){ }elseif($dev < 0.95){
$html .= "<span class='float-right text-danger-emphasis'> $html .= "<span class='float-right text-danger-emphasis'>
<i class='bi bi-arrow-".$arrowBad."' style='font-size: 0.9em;'></i> "; <i class='bi bi-arrow-".$arrowBad."' style='font-size: 0.9em;'></i> ";
}else{ }else{
$html .= "<span class='float-right'> $html .= "<span class='float-right'>
<i class='bi bi-arrow-right' style='font-size: 0.9em;'></i> "; <i class='bi bi-arrow-right' style='font-size: 0.9em;'></i> ";
} }
} }
else{ else{
$html .= "<span class='float-right'>"; $html .= "<span class='float-right'>";
} }
$html .= number_format(floatval($value),2,",",".") $html .= number_format(floatval($value),2,",",".")
."<small> ".$units[$i]."</small></span></div> ."<small> ".$units[$i]."</small></span></div>
<!-- /.info-box-content --> <!-- /.info-box-content -->
</div> </div>
</div>"; </div>";
$i++; $i++;
} }
} }
$html .= "</div>"; $html .= "</div>";
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo $html; echo $html;
//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]}]}'; //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]}]}';

View File

@ -1,65 +1,65 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
if(!isset($_GET["TO"])){ if(!isset($_GET["TO"])){
$_GET["TO"] = 12; $_GET["TO"] = 12;
} }
$_GET["TO"] = intval($_GET["TO"]); $_GET["TO"] = intval($_GET["TO"]);
if(!isset($_GET["FROM"])){ if(!isset($_GET["FROM"])){
$_GET["FROM"] = -24; $_GET["FROM"] = -24;
} }
$_GET["FROM"] = intval($_GET["FROM"]); $_GET["FROM"] = intval($_GET["FROM"]);
$Query = "SELECT $Query = "SELECT
UNIX_TIMESTAMP(CONCAT(date,' ',sunrise)) AS sunrise, UNIX_TIMESTAMP(CONCAT(date,' ',sunrise)) AS sunrise,
UNIX_TIMESTAMP(CONCAT(date,' ',sunset)) AS sunset UNIX_TIMESTAMP(CONCAT(date,' ',sunset)) AS sunset
FROM solarLog.daylight FROM solarLog.daylight
WHERE date BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"]-24)." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR) WHERE date BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"]-24)." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR)
ORDER BY date"; ORDER BY date";
$linecolors["Solarleistung"] = "#FFFF00"; $linecolors["Solarleistung"] = "#FFFF00";
$linecolors["UG"] = "#FFaa00"; $linecolors["UG"] = "#FFaa00";
$linecolors["OG"] = "#FF4400"; $linecolors["OG"] = "#FF4400";
$linecolors["Auto UG"] = "#00aaFF"; $linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF"; $linecolors["Auto OG"] = "#0044FF";
$linecolors["Heizstab"] = "#FF0000"; $linecolors["Heizstab"] = "#FF0000";
$linecolors["Batterieladung"] = "#00aa00"; $linecolors["Batterieladung"] = "#00aa00";
$linecolors["Einspeisung"] = "#b0b0b0"; $linecolors["Einspeisung"] = "#b0b0b0";
$linecolors["Ladestand"] = "#00aa00"; $linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#2222FF"; $linecolors["Vorhersage"] = "#2222FF";
if (checkLogin()) { if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $Query); $result = mysqli_query($mysql, $Query);
if (!$result) { if (!$result) {
echo "Error:<br>" . mysqli_error($mysql) . "<br />"; echo "Error:<br>" . mysqli_error($mysql) . "<br />";
} }
//$obj[] = (object)[]; // Cast empty array to object //$obj[] = (object)[]; // Cast empty array to object
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$ii = 1; $ii = 1;
$anno = (object)[]; $anno = (object)[];
if($row["sunrise"] < (time()+$_GET["FROM"]*60*60)){ if($row["sunrise"] < (time()+$_GET["FROM"]*60*60)){
$anno->xMin = (time()+$_GET["FROM"]*60*60)*1000; $anno->xMin = (time()+$_GET["FROM"]*60*60)*1000;
}else{ }else{
$anno->xMin = $row["sunrise"]*1000; $anno->xMin = $row["sunrise"]*1000;
} }
if($row["sunset"] > (time()+$_GET["TO"]*60*60)){ if($row["sunset"] > (time()+$_GET["TO"]*60*60)){
$anno->xMax = round(time()+$_GET["TO"]*60*60)*1000; $anno->xMax = round(time()+$_GET["TO"]*60*60)*1000;
}else{ }else{
$anno->xMax = $row["sunset"]*1000; $anno->xMax = $row["sunset"]*1000;
} }
$anno->borderWidth = 0; $anno->borderWidth = 0;
if($row["sunset"] > (time()+$_GET["FROM"]*60*60)){ if($row["sunset"] > (time()+$_GET["FROM"]*60*60)){
$obj[] = clone $anno; $obj[] = clone $anno;
} }
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';

View File

@ -1,65 +1,65 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
$waterQuery = "SELECT UNIX_TIMESTAMP(datetime) AS time, rate AS 'Wasserverbrauch' $waterQuery = "SELECT UNIX_TIMESTAMP(datetime) AS time, rate AS 'Wasserverbrauch'
FROM solarLog.wasser FROM solarLog.wasser
WHERE wasser.datetime BETWEEN DATE_SUB(NOW(),INTERVAL 24 HOUR) and NOW() WHERE wasser.datetime BETWEEN DATE_SUB(NOW(),INTERVAL 24 HOUR) and NOW()
ORDER BY wasser.datetime"; ORDER BY wasser.datetime";
$linecolors["Speicher oben"] = "#FF5500"; $linecolors["Speicher oben"] = "#FF5500";
$linecolors["Speicher mitte"] = "#FFaa00"; $linecolors["Speicher mitte"] = "#FFaa00";
$linecolors["Speicher unten"] = "#FFFF00"; $linecolors["Speicher unten"] = "#FFFF00";
$linecolors["Therme Vorlauf Fußboden"] = "#bb0000"; $linecolors["Therme Vorlauf Fußboden"] = "#bb0000";
$linecolors["Therme Rücklauf"] = "#ee0000"; $linecolors["Therme Rücklauf"] = "#ee0000";
$linecolors["Heizstab Vorlauf"] = "#9900bb"; $linecolors["Heizstab Vorlauf"] = "#9900bb";
$linecolors["Heizstab Rücklauf"] = "#8800aa"; $linecolors["Heizstab Rücklauf"] = "#8800aa";
$linecolors["Fußboden Vorlauf"] = "#00FF00"; $linecolors["Fußboden Vorlauf"] = "#00FF00";
$linecolors["Fußboden Rücklauf"] = "#00aa00"; $linecolors["Fußboden Rücklauf"] = "#00aa00";
$linecolors["Wasserverbrauch"] = "#2222FF"; $linecolors["Wasserverbrauch"] = "#2222FF";
if (checkLogin()) { if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$waterRes = mysqli_query($mysql,$waterQuery); $waterRes = mysqli_query($mysql,$waterQuery);
if(!$waterRes){ if(!$waterRes){
echo "Error:<br>".mysqli_error($mysql)."<br />"; echo "Error:<br>".mysqli_error($mysql)."<br />";
} }
$obj = (object)[]; // Cast empty array to object $obj = (object)[]; // Cast empty array to object
$obj->labels = []; $obj->labels = [];
$obj->datasets = []; $obj->datasets = [];
$i = 0; $i = 0;
$filled = 0; $filled = 0;
if ($waterRes->num_rows > 1) { if ($waterRes->num_rows > 1) {
$dataset = (object)[]; $dataset = (object)[];
$row = $waterRes->fetch_assoc(); $row = $waterRes->fetch_assoc();
$dataset->borderColor = $linecolors["Wasserverbrauch"]; $dataset->borderColor = $linecolors["Wasserverbrauch"];
$dataset->backgroundColor = $linecolors["Wasserverbrauch"]."00"; $dataset->backgroundColor = $linecolors["Wasserverbrauch"]."00";
$dataset->borderWidth=2; $dataset->borderWidth=2;
$dataset->pointRadius= 0; $dataset->pointRadius= 0;
$dataset->pointHoverRadius= 5; $dataset->pointHoverRadius= 5;
$dataset->tension=0.2; $dataset->tension=0.2;
$dataset->fill = "none"; $dataset->fill = "none";
$dataset->yAxisID = 'y1'; $dataset->yAxisID = 'y1';
$dataset->label = "Wasserverbrauch"; $dataset->label = "Wasserverbrauch";
$pt = (object)[]; $pt = (object)[];
$pt->x = $row["time"]*1000; $pt->x = $row["time"]*1000;
$pt->y = $row["Wasserverbrauch"]; $pt->y = $row["Wasserverbrauch"];
$dataset->data[] = clone $pt; $dataset->data[] = clone $pt;
while ($row = $waterRes->fetch_assoc()) { while ($row = $waterRes->fetch_assoc()) {
$pt = (object)[]; $pt = (object)[];
$pt->x = $row["time"]*1000; $pt->x = $row["time"]*1000;
$pt->y = $row["Wasserverbrauch"]; $pt->y = $row["Wasserverbrauch"];
$dataset->data[] = clone $pt; $dataset->data[] = clone $pt;
} }
$obj->datasets[] = clone $dataset; $obj->datasets[] = clone $dataset;
} }
} }
//header('Content-Type: application/json'); //header('Content-Type: application/json');
echo json_encode($obj); 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]}]}'; //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]}]}';

View File

@ -1,73 +1,73 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
function getSSLPage($url) { function getSSLPage($url) {
$curlSession = curl_init(); $curlSession = curl_init();
curl_setopt($curlSession, CURLOPT_URL, $url); curl_setopt($curlSession, CURLOPT_URL, $url);
curl_setopt($curlSession, CURLOPT_BINARYTRANSFER, true); curl_setopt($curlSession, CURLOPT_BINARYTRANSFER, true);
curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true); curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true);
$jsonData = json_decode(curl_exec($curlSession),true); $jsonData = json_decode(curl_exec($curlSession),true);
curl_close($curlSession); curl_close($curlSession);
return $jsonData; return $jsonData;
} }
if (checkLogin()) { if (checkLogin()) {
$close = 0; $close = 0;
$hostname = "192.168.179.169"; $hostname = "192.168.179.169";
if (isset($_POST["setMode"]) || isset($_GET["setMode"])) { if (isset($_POST["setMode"]) || isset($_GET["setMode"])) {
//send new value //send new value
$_POST["setMode"] = intval($_POST["setMode"]) + intval($_GET["setMode"]); $_POST["setMode"] = intval($_POST["setMode"]) + intval($_GET["setMode"]);
if($_POST["setMode"] > 0 && $_POST["setMode"] < 60){ if($_POST["setMode"] > 0 && $_POST["setMode"] < 60){
$pwr = $_POST["setMode"]*100; $pwr = $_POST["setMode"]*100;
$headers[] = "GET /set?mode=man&pwr=".$pwr." HTTP/1.1"; $headers[] = "GET /set?mode=man&pwr=".$pwr." HTTP/1.1";
$headers[] = "Host: ".$hostname; $headers[] = "Host: ".$hostname;
$headers[] = ""; $headers[] = "";
$remote = fsockopen("tcp://".$hostname, 80, $errno, $errstr, 5); $remote = fsockopen("tcp://".$hostname, 80, $errno, $errstr, 5);
fwrite($remote, implode("\r\n", $headers)."\r\n"); fwrite($remote, implode("\r\n", $headers)."\r\n");
$file = ''; $file = '';
$file .= fread($remote, 1024); $file .= fread($remote, 1024);
fclose($remote); fclose($remote);
}elseif($_POST["setMode"] == 0){ }elseif($_POST["setMode"] == 0){
$headers[] = "GET /set?mode=eco&pwr=0 HTTP/1.1"; $headers[] = "GET /set?mode=eco&pwr=0 HTTP/1.1";
$headers[] = "Host: ".$hostname; $headers[] = "Host: ".$hostname;
$headers[] = ""; $headers[] = "";
$remote = fsockopen("tcp://".$hostname, 80, $errno, $errstr, 5); $remote = fsockopen("tcp://".$hostname, 80, $errno, $errstr, 5);
fwrite($remote, implode("\r\n", $headers)."\r\n"); fwrite($remote, implode("\r\n", $headers)."\r\n");
$file = ''; $file = '';
$file .= fread($remote, 1024); $file .= fread($remote, 1024);
fclose($remote); fclose($remote);
} }
$close = 1; $close = 1;
} }
} else { } else {
$close = 1; $close = 1;
} }
if (!$close) { if (!$close) {
echo <<<ENDE echo <<<ENDE
<style> <style>
input[type='range']::-webkit-slider-runnable-track { input[type='range']::-webkit-slider-runnable-track {
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7; background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
background-size: var(--background-size, 0%) 100%; background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
</style> </style>
<!--begin::Form--> <!--begin::Form-->
<form id="heater_form"> <form id="heater_form">
<div class="col-sm-11"> <div class="col-sm-11">
<div class="form-check"> <div class="form-check">
<label class="form-label" for="addedCharge">Leistung: </label> <label class="form-label" for="addedCharge">Leistung: </label>
<div style="font-size: 15px;color: #297195;display: inline-block;" id="modal-slider-label">0</div> <div style="font-size: 15px;color: #297195;display: inline-block;" id="modal-slider-label">0</div>
<input type="range" id="modal-slider" name="setMode" class="form-range range-color-track" min="0" max="60" /> <input type="range" id="modal-slider" name="setMode" class="form-range range-color-track" min="0" max="60" />
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">Auto</span> <span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">Auto</span>
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">6.0 kW</span> <span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">6.0 kW</span>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
ENDE; ENDE;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,55 +1,55 @@
<?php <?php
require_once("./phpMQTT.php"); require_once("./phpMQTT.php");
require_once("../helper.php"); require_once("../helper.php");
if (checkLogin()) { if (checkLogin()) {
$close = 0; $close = 0;
$hostname = "192.168.179.169"; $hostname = "192.168.179.169";
$server = 'localhost'; // change if necessary $server = 'localhost'; // change if necessary
$port = 1883; // change if necessary $port = 1883; // change if necessary
$username = ''; // set your username $username = ''; // set your username
$password = ''; // set your password $password = ''; // set your password
$client_id = 'RoomtempSetter'; // make sure this is unique for connecting to sever - you could use uniqid() $client_id = 'RoomtempSetter'; // make sure this is unique for connecting to sever - you could use uniqid()
if (isset($_POST["setTemp"]) && isset($_GET["heater"])) { if (isset($_POST["setTemp"]) && isset($_GET["heater"])) {
$topic = "Raumtemp/".str_replace("_","/",$_GET["heater"])."/changeSetTemp"; $topic = "Raumtemp/".str_replace("_","/",$_GET["heater"])."/changeSetTemp";
$mqtt = new Bluerhinos\phpMQTT($server, $port, $client_id); $mqtt = new Bluerhinos\phpMQTT($server, $port, $client_id);
//send new value //send new value
$temp = intval($_POST["setTemp"]); $temp = intval($_POST["setTemp"]);
if($temp > 9 && $temp < 31){ if($temp > 9 && $temp < 31){
if ($mqtt->connect(true, NULL, $username, $password)) { if ($mqtt->connect(true, NULL, $username, $password)) {
$mqtt->publish($topic, $temp, 0, false); $mqtt->publish($topic, $temp, 0, false);
$mqtt->close(); $mqtt->close();
} }
} }
$close = 1; $close = 1;
} }
} else { } else {
$close = 1; $close = 1;
} }
if (!$close) { if (!$close) {
echo <<<ENDE echo <<<ENDE
<style> <style>
input[type='range']::-webkit-slider-runnable-track { input[type='range']::-webkit-slider-runnable-track {
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7; background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
background-size: var(--background-size, 0%) 100%; background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
</style> </style>
<!--begin::Form--> <!--begin::Form-->
<form id="heater_form"> <form id="heater_form">
<div class="col-sm-11"> <div class="col-sm-11">
<div class="form-check"> <div class="form-check">
<label class="form-label" for="addedCharge">Temperatur: </label> <label class="form-label" for="addedCharge">Temperatur: </label>
<div style="font-size: 15px;color: #297195;display: inline-block;" id="modal-slider-label">0</div> <div style="font-size: 15px;color: #297195;display: inline-block;" id="modal-slider-label">0</div>
<input type="range" id="modal-slider" name="setTemp" class="form-range range-color-track" min="10" max="30" /> <input type="range" id="modal-slider" name="setTemp" class="form-range range-color-track" min="10" max="30" />
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">10 °C</span> <span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">10 °C</span>
<span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">30 °C</span> <span class="max-amount f-16 font-weight-normal darkGray-color text-right mt-1">30 °C</span>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
ENDE; ENDE;
} }

View File

@ -1,12 +1,12 @@
<?php <?php
require_once("../helper.php"); require_once("../helper.php");
if(isset($_GET["sensorID"])){ if(isset($_GET["sensorID"])){
$sensorID = intval($_GET["sensorID"]); $sensorID = intval($_GET["sensorID"]);
$qry = "SELECT parameters FROM sensors WHERE id=".$sensorID; $qry = "SELECT parameters FROM sensors WHERE id=".$sensorID;
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB); $mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $qry); $result = mysqli_query($mysql, $qry);
echo $result->fetch_array()[0]; echo $result->fetch_array()[0];
} }
?> ?>

View File

@ -1,241 +1,241 @@
<?php <?php
set_time_limit(60); set_time_limit(60);
ob_start(); ob_start();
require_once("../restricted/tahoma_EG.php"); require_once("../restricted/tahoma_EG.php");
//67ebd23e3a61763386d9 //67ebd23e3a61763386d9
function getSSLPage($url, $tahoma_token) function getSSLPage($url, $tahoma_token)
{ {
$ch = curl_init(); $ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', "Authorization: Bearer ".$tahoma_token)); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', "Authorization: Bearer ".$tahoma_token));
curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSLVERSION, 3); curl_setopt($ch, CURLOPT_SSLVERSION, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch); $result = curl_exec($ch);
if (curl_errno($ch)) { if (curl_errno($ch)) {
$error_msg = curl_error($ch); $error_msg = curl_error($ch);
//print $error_msg; //print $error_msg;
} }
curl_close($ch); curl_close($ch);
return $result; return $result;
} }
function postSSLPage($url, $body, $tahoma_token) function postSSLPage($url, $body, $tahoma_token)
{ {
$ch = curl_init(); $ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', "Authorization: Bearer ".$tahoma_token)); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', "Authorization: Bearer ".$tahoma_token));
curl_setopt($ch, CURLOPT_POSTFIELDS, $body); curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSLVERSION, 3); curl_setopt($ch, CURLOPT_SSLVERSION, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch); $result = curl_exec($ch);
if (curl_errno($ch)) { if (curl_errno($ch)) {
$error_msg = curl_error($ch); $error_msg = curl_error($ch);
//print $error_msg; //print $error_msg;
} }
curl_close($ch); curl_close($ch);
return $result; return $result;
} }
function filter_devs($arr,$filter,$prefix=""){ function filter_devs($arr,$filter,$prefix=""){
$ret = Array(); $ret = Array();
$i = 0; $i = 0;
foreach($arr as $key => $dev){ foreach($arr as $key => $dev){
$start = strpos(strtolower($dev["name"]),strtolower($filter)); $start = strpos(strtolower($dev["name"]),strtolower($filter));
if($start !== false){ if($start !== false){
$ret[$i]["name"] = $prefix.substr($dev["name"],strlen($filter)); $ret[$i]["name"] = $prefix.substr($dev["name"],strlen($filter));
$ret[$i]["id"] = $key; $ret[$i]["id"] = $key;
$i++; $i++;
} }
} }
return $ret; return $ret;
} }
function searchForDevice($device){ function searchForDevice($device){
$dev = false; $dev = false;
$devices = json_decode(file_get_contents('../restricted/tahoma_devices.json'), true); $devices = json_decode(file_get_contents('../restricted/tahoma_devices.json'), true);
if (strlen($device) < 3 && intval($device) >= 0 && intval($device) < sizeof($devices)) { if (strlen($device) < 3 && intval($device) >= 0 && intval($device) < sizeof($devices)) {
$dev = $devices[intval($device)]; $dev = $devices[intval($device)];
} else if ($key = array_search($device, array_column($devices, "name"))) { } else if ($key = array_search($device, array_column($devices, "name"))) {
$dev = $devices[$key]; $dev = $devices[$key];
} else if ($key = array_search($device, array_column($devices, "id"))) { } else if ($key = array_search($device, array_column($devices, "id"))) {
$dev = $devices[$key]; $dev = $devices[$key];
} else { } else {
return false; return false;
} }
return $dev; return $dev;
} }
if ($_GET["action"] == "devlist") { if ($_GET["action"] == "devlist") {
$jalousien = array(); $jalousien = array();
$url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/setup/devices'; $url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/setup/devices';
$ret = getSSLPage($url,$tahoma_token); $ret = getSSLPage($url,$tahoma_token);
$devices = json_decode($ret, true); $devices = json_decode($ret, true);
$i = 0; $i = 0;
foreach ($devices as $device) { foreach ($devices as $device) {
if ($device["controllableName"] == "io:ExteriorVenetianBlindIOComponent") { if ($device["controllableName"] == "io:ExteriorVenetianBlindIOComponent") {
$jalousien[$i]["name"] = $device["label"]; $jalousien[$i]["name"] = $device["label"];
$jalousien[$i]["id"] = $device["deviceURL"]; $jalousien[$i]["id"] = $device["deviceURL"];
$i = $i + 1; $i = $i + 1;
echo $device["label"] . "(".$device["deviceURL"].")<br />"; echo $device["label"] . "(".$device["deviceURL"].")<br />";
} }
} }
$file = fopen('../restricted/tahoma_devices.json', 'w'); $file = fopen('../restricted/tahoma_devices.json', 'w');
fwrite($file, json_encode($jalousien)); fwrite($file, json_encode($jalousien));
fclose($file); fclose($file);
}elseif ($_GET["action"] == "pos" && isset($_GET["device"])) { }elseif ($_GET["action"] == "pos" && isset($_GET["device"])) {
$dev = searchForDevice($_GET["device"])["id"]; $dev = searchForDevice($_GET["device"])["id"];
$devices = json_decode(file_get_contents('../restricted/tahoma_devices.json'), true); $devices = json_decode(file_get_contents('../restricted/tahoma_devices.json'), true);
$jalousien = array(); $jalousien = array();
$url = $url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/setup/devices/'.urlencode($dev)."/states"; $url = $url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/setup/devices/'.urlencode($dev)."/states";
$ret = getSSLPage($url,$tahoma_token); $ret = getSSLPage($url,$tahoma_token);
$states = json_decode($ret, true); $states = json_decode($ret, true);
$out = "{"; $out = "{";
foreach ($states as $state){ foreach ($states as $state){
if ($state["name"] == "core:SlateOrientationState") if ($state["name"] == "core:SlateOrientationState")
$out .= "\"rotation\":".$state["value"].","; $out .= "\"rotation\":".$state["value"].",";
if ($state["name"] == "core:ClosureState") if ($state["name"] == "core:ClosureState")
$out .= "\"position\":".$state["value"].","; $out .= "\"position\":".$state["value"].",";
} }
$out = substr($out,0,-1); $out = substr($out,0,-1);
$out .= "}"; $out .= "}";
echo $out; echo $out;
header('Connection: close'); header('Connection: close');
header('Content-Length: '.ob_get_length()); header('Content-Length: '.ob_get_length());
ob_end_flush(); ob_end_flush();
@ob_flush(); @ob_flush();
flush(); flush();
fastcgi_finish_request(); fastcgi_finish_request();
}elseif ($_GET["action"] == "moving" && isset($_GET["device"])) { }elseif ($_GET["action"] == "moving" && isset($_GET["device"])) {
$dev = searchForDevice($_GET["device"])["id"]; $dev = searchForDevice($_GET["device"])["id"];
$devices = json_decode(file_get_contents('../restricted/tahoma_devices.json'), true); $devices = json_decode(file_get_contents('../restricted/tahoma_devices.json'), true);
$jalousien = array(); $jalousien = array();
$url = $url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/setup/devices/'.urlencode($dev)."/states/core:MovingState"; $url = $url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/setup/devices/'.urlencode($dev)."/states/core:MovingState";
$ret = getSSLPage($url,$tahoma_token); $ret = getSSLPage($url,$tahoma_token);
$moving = json_decode($ret, true); $moving = json_decode($ret, true);
if($moving["value"]) if($moving["value"])
echo "true"; echo "true";
else else
echo "false"; echo "false";
header('Connection: close'); header('Connection: close');
header('Content-Length: '.ob_get_length()); header('Content-Length: '.ob_get_length());
ob_end_flush(); ob_end_flush();
@ob_flush(); @ob_flush();
flush(); flush();
fastcgi_finish_request(); fastcgi_finish_request();
}elseif ($_GET["action"] == "move" && isset($_GET["pos"]) && isset($_GET["angle"]) && isset($_GET["device"])) { }elseif ($_GET["action"] == "move" && isset($_GET["pos"]) && isset($_GET["angle"]) && isset($_GET["device"])) {
$angle = $_GET["angle"]; $angle = $_GET["angle"];
$pos = $_GET["pos"]; $pos = $_GET["pos"];
if ($pos < 0 || $pos > 100) { if ($pos < 0 || $pos > 100) {
echo "Position out of Range"; echo "Position out of Range";
exit; exit;
} }
if ($angle < 0 || $angle > 100) { if ($angle < 0 || $angle > 100) {
echo "Angle out of Range"; echo "Angle out of Range";
exit; exit;
} }
$dev = searchForDevice($_GET["device"])["id"]; $dev = searchForDevice($_GET["device"])["id"];
if($dev == false){ if($dev == false){
exit; exit;
} }
header('Connection: close'); header('Connection: close');
header('Content-Length: '.ob_get_length()); header('Content-Length: '.ob_get_length());
$url = $url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/setup/devices/'.urlencode($dev)."/states/core:MovingState"; $url = $url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/setup/devices/'.urlencode($dev)."/states/core:MovingState";
$ret = json_decode(getSSLPage($url,$tahoma_token),true); $ret = json_decode(getSSLPage($url,$tahoma_token),true);
$action = array(); $action = array();
$action["label"] = "myAction"; $action["label"] = "myAction";
$action["actions"] = array(); $action["actions"] = array();
$action["actions"][0]["deviceURL"] = $dev; $action["actions"][0]["deviceURL"] = $dev;
$action["actions"][0]["commands"] = array(); $action["actions"][0]["commands"] = array();
if(!isset($ret["value"])){ if(!isset($ret["value"])){
$ret = json_decode(getSSLPage($url,$tahoma_token),true); $ret = json_decode(getSSLPage($url,$tahoma_token),true);
} }
if(!isset($ret["value"]) || $ret["value"] == false){ if(!isset($ret["value"]) || $ret["value"] == false){
$url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/exec/apply'; $url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/exec/apply';
echo "start"; echo "start";
ob_end_flush(); ob_end_flush();
@ob_flush(); @ob_flush();
flush(); flush();
fastcgi_finish_request(); fastcgi_finish_request();
$action["actions"][0]["commands"][0]["name"] = "setClosureAndOrientation"; $action["actions"][0]["commands"][0]["name"] = "setClosureAndOrientation";
$action["actions"][0]["commands"][0]["parameters"][0] = intval($pos); $action["actions"][0]["commands"][0]["parameters"][0] = intval($pos);
$action["actions"][0]["commands"][0]["parameters"][1] = intval($angle); $action["actions"][0]["commands"][0]["parameters"][1] = intval($angle);
$res = json_decode(postSSLPage($url,json_encode($action),$tahoma_token)); $res = json_decode(postSSLPage($url,json_encode($action),$tahoma_token));
if(!isset($res["execId"])){ if(!isset($res["execId"])){
sleep(1); sleep(1);
$res = json_decode(postSSLPage($url,json_encode($action),$tahoma_token)); //2nd try $res = json_decode(postSSLPage($url,json_encode($action),$tahoma_token)); //2nd try
} }
}elseif($ret["value"] == true){ }elseif($ret["value"] == true){
$url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/exec/apply'; $url = 'https://gateway-'.$tahoma_PIN.':8443/enduser-mobile-web/1/enduserAPI/exec/apply';
echo "stop"; echo "stop";
ob_end_flush(); ob_end_flush();
@ob_flush(); @ob_flush();
flush(); flush();
fastcgi_finish_request(); fastcgi_finish_request();
$action["actions"][0]["commands"][0]["name"] = "stop"; $action["actions"][0]["commands"][0]["name"] = "stop";
$res = json_decode(postSSLPage($url,json_encode($action),$tahoma_token)); $res = json_decode(postSSLPage($url,json_encode($action),$tahoma_token));
if(!isset($res["execId"])){ if(!isset($res["execId"])){
sleep(1); sleep(1);
$res = json_decode(postSSLPage($url,json_encode($action),$tahoma_token)); //2nd try $res = json_decode(postSSLPage($url,json_encode($action),$tahoma_token)); //2nd try
} }
} }
} }
if ($_GET["action"] == "myactors") { if ($_GET["action"] == "myactors") {
if(isset($_GET["filter"])){ if(isset($_GET["filter"])){
$host = $_GET["filter"]; $host = $_GET["filter"];
$host = str_replace("-", "", strtolower($host)); $host = str_replace("-", "", strtolower($host));
}else{ }else{
$host = gethostbyaddr("192.168.179.32"); $host = gethostbyaddr("192.168.179.32");
$host = str_replace("-", "", strtolower(substr($host, 0, strpos($host, ".")))); $host = str_replace("-", "", strtolower(substr($host, 0, strpos($host, "."))));
} }
$devices = json_decode(file_get_contents('../restricted/tahoma_devices.json'), true); $devices = json_decode(file_get_contents('../restricted/tahoma_devices.json'), true);
switch ($host) { switch ($host) {
case "tmpegbad": case "tmpegbad":
echo json_encode(filter_devs($devices, "bad ")); echo json_encode(filter_devs($devices, "bad "));
break; break;
case "tmpegwozi": case "tmpegwozi":
echo json_encode(filter_devs($devices, "wozi ")); echo json_encode(filter_devs($devices, "wozi "));
break; break;
case "tmpegflorian": //flori case "tmpegflorian": //flori
$ret = filter_devs($devices, "florian ","Flori "); $ret = filter_devs($devices, "florian ","Flori ");
$ret = array_merge($ret, filter_devs($devices, "magdalena ","Magdalena ")); $ret = array_merge($ret, filter_devs($devices, "magdalena ","Magdalena "));
echo json_encode($ret); echo json_encode($ret);
break; break;
case "tmpegmagdalena": case "tmpegmagdalena":
echo json_encode(filter_devs($devices, "magdalena ")); echo json_encode(filter_devs($devices, "magdalena "));
break; break;
case "tmpegschlafzimmer": case "tmpegschlafzimmer":
echo json_encode(filter_devs($devices, "schlafzimmer ")); echo json_encode(filter_devs($devices, "schlafzimmer "));
break; break;
default: default:
$ret2=Array(); $ret2=Array();
//$ret2[0]["name"] = $host; //$ret2[0]["name"] = $host;
//$ret2[0]["id"] = 99; //$ret2[0]["id"] = 99;
$ret = filter_devs($devices, ""); $ret = filter_devs($devices, "");
//$ret = array_merge($ret, $ret2); //$ret = array_merge($ret, $ret2);
echo json_encode($ret); echo json_encode($ret);
break; break;
} }
header('Connection: close'); header('Connection: close');
header('Content-Length: '.ob_get_length()); header('Content-Length: '.ob_get_length());
ob_end_flush(); ob_end_flush();
@ob_flush(); @ob_flush();
flush(); flush();
fastcgi_finish_request(); fastcgi_finish_request();
//echo postSSLPage($url,json_encode($action)); //echo postSSLPage($url,json_encode($action));
} }

View File

@ -1,144 +1,144 @@
/* devanagari */ /* devanagari */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 200; font-weight: 200;
src: url(pxiByp8kv8JHgFVrLFj_Z11lFc-K.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLFj_Z11lFc-K.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09; unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
} }
/* latin-ext */ /* latin-ext */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 200; font-weight: 200;
src: url(pxiByp8kv8JHgFVrLFj_Z1JlFc-K.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLFj_Z1JlFc-K.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
} }
/* latin */ /* latin */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 200; font-weight: 200;
src: url(pxiByp8kv8JHgFVrLFj_Z1xlFQ.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLFj_Z1xlFQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
/* devanagari */ /* devanagari */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: url(pxiByp8kv8JHgFVrLDz8Z11lFc-K.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLDz8Z11lFc-K.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09; unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
} }
/* latin-ext */ /* latin-ext */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: url(pxiByp8kv8JHgFVrLDz8Z1JlFc-K.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLDz8Z1JlFc-K.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
} }
/* latin */ /* latin */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: url(pxiByp8kv8JHgFVrLDz8Z1xlFQ.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLDz8Z1xlFQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
/* devanagari */ /* devanagari */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url(pxiEyp8kv8JHgFVrJJbecmNE.woff2) format('woff2'); src: url(pxiEyp8kv8JHgFVrJJbecmNE.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09; unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
} }
/* latin-ext */ /* latin-ext */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url(pxiEyp8kv8JHgFVrJJnecmNE.woff2) format('woff2'); src: url(pxiEyp8kv8JHgFVrJJnecmNE.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
} }
/* latin */ /* latin */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url(pxiEyp8kv8JHgFVrJJfecg.woff2) format('woff2'); src: url(pxiEyp8kv8JHgFVrJJfecg.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
/* devanagari */ /* devanagari */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: url(pxiByp8kv8JHgFVrLEj6Z11lFc-K.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLEj6Z11lFc-K.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09; unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
} }
/* latin-ext */ /* latin-ext */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: url(pxiByp8kv8JHgFVrLEj6Z1JlFc-K.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLEj6Z1JlFc-K.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
} }
/* latin */ /* latin */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: url(pxiByp8kv8JHgFVrLEj6Z1xlFQ.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLEj6Z1xlFQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
/* devanagari */ /* devanagari */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: url(pxiByp8kv8JHgFVrLCz7Z11lFc-K.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLCz7Z11lFc-K.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09; unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
} }
/* latin-ext */ /* latin-ext */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: url(pxiByp8kv8JHgFVrLCz7Z1JlFc-K.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLCz7Z1JlFc-K.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
} }
/* latin */ /* latin */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: url(pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
/* devanagari */ /* devanagari */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 800; font-weight: 800;
src: url(pxiByp8kv8JHgFVrLDD4Z11lFc-K.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLDD4Z11lFc-K.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09; unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
} }
/* latin-ext */ /* latin-ext */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 800; font-weight: 800;
src: url(pxiByp8kv8JHgFVrLDD4Z1JlFc-K.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLDD4Z1JlFc-K.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
} }
/* latin */ /* latin */
@font-face { @font-face {
font-family: 'Poppins'; font-family: 'Poppins';
font-style: normal; font-style: normal;
font-weight: 800; font-weight: 800;
src: url(pxiByp8kv8JHgFVrLDD4Z1xlFQ.woff2) format('woff2'); src: url(pxiByp8kv8JHgFVrLDD4Z1xlFQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }

View File

@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#fff" <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#fff"
class="bi bi-heart-arrow" viewBox="0 0 16 16"> class="bi bi-heart-arrow" viewBox="0 0 16 16">
<path <path
d="M6.707 9h4.364c-.536 1.573 2.028 3.806 4.929-.5-2.9-4.306-5.465-2.073-4.929-.5H6.707L4.854 6.146a.5.5 0 1 0-.708.708L5.293 8h-.586L2.854 6.146a.5.5 0 1 0-.708.708L3.293 8h-.586L.854 6.146a.5.5 0 1 0-.708.708L1.793 8.5.146 10.146a.5.5 0 0 0 .708.708L2.707 9h.586l-1.147 1.146a.5.5 0 0 0 .708.708L4.707 9h.586l-1.147 1.146a.5.5 0 0 0 .708.708z" /> d="M6.707 9h4.364c-.536 1.573 2.028 3.806 4.929-.5-2.9-4.306-5.465-2.073-4.929-.5H6.707L4.854 6.146a.5.5 0 1 0-.708.708L5.293 8h-.586L2.854 6.146a.5.5 0 1 0-.708.708L3.293 8h-.586L.854 6.146a.5.5 0 1 0-.708.708L1.793 8.5.146 10.146a.5.5 0 0 0 .708.708L2.707 9h.586l-1.147 1.146a.5.5 0 0 0 .708.708L4.707 9h.586l-1.147 1.146a.5.5 0 0 0 .708.708z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 491 B

After

Width:  |  Height:  |  Size: 495 B

View File

@ -1,287 +1,287 @@
<svg xmlns="http://www.w3.org/2000/svg" style="border:0px solid gray;background-color: #212529;" viewBox="0 0 630 750" width= "100%" height= "100%"> <svg xmlns="http://www.w3.org/2000/svg" style="border:0px solid gray;background-color: #212529;" viewBox="0 0 630 750" width= "100%" height= "100%">
<g style="fill:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;stroke:#666666;fill:#666666;" stroke-width="10" transform="scale (2) translate(0 -25)"> <g style="fill:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;stroke:#666666;fill:#666666;" stroke-width="10" transform="scale (2) translate(0 -25)">
<path <path
id="Puffer" id="Puffer"
d="m 227,68 c 0,0 0,-28 -74,-28 -75,0 -75,27 -75,27 V 353 c 0,0 10,31 76,31 66,0 75,-32 75,-32 z" d="m 227,68 c 0,0 0,-28 -74,-28 -75,0 -75,27 -75,27 V 353 c 0,0 10,31 76,31 66,0 75,-32 75,-32 z"
style="fill:#212529;fill-opacity:1;stroke-width:2;" /> style="fill:#212529;fill-opacity:1;stroke-width:2;" />
<ellipse <ellipse
ry="3" ry="3"
rx="1" rx="1"
cy="112" cy="112"
cx="211" cx="211"
id="path902" /> id="path902" />
<ellipse <ellipse
ry="5" ry="5"
rx="3" rx="3"
cy="163" cy="163"
cx="211" cx="211"
id="path904" /> id="path904" />
<ellipse <ellipse
ry="5" ry="5"
rx="3" rx="3"
cy="282" cy="282"
cx="210" cx="210"
id="path904-6" /> id="path904-6" />
<ellipse <ellipse
ry="5" ry="5"
rx="3" rx="3"
cy="345" cy="345"
cx="213" cx="213"
id="path904-2" /> id="path904-2" />
<ellipse <ellipse
ry="3" ry="3"
rx="1" rx="1"
cy="332" cy="332"
cx="213" cx="213"
id="path902-4" /> id="path902-4" />
<ellipse <ellipse
ry="3" ry="3"
rx="1" rx="1"
cy="121" cy="121"
cx="100" cx="100"
id="path902-0" /> id="path902-0" />
<ellipse <ellipse
ry="3" ry="3"
rx="1" rx="1"
cy="164" cy="164"
cx="99" /> cx="99" />
<ellipse <ellipse
ry="3" ry="3"
rx="1" rx="1"
cy="175" cy="175"
cx="99" cx="99"
id="path902-8" /> id="path902-8" />
<ellipse <ellipse
ry="3" ry="3"
rx="1" rx="1"
cy="223" cy="223"
cx="98" cx="98"
id="path902-2" /> id="path902-2" />
<ellipse <ellipse
ry="3" ry="3"
rx="1" rx="1"
cy="257" cy="257"
cx="98" cx="98"
id="path902-07" /> id="path902-07" />
<path <path
id="heatweRLtube1" id="heatweRLtube1"
d="m 211,282 h 95 v -44" d="m 211,282 h 95 v -44"
style="fill:none;" /> style="fill:none;" />
<path <path
id="path976" id="path976"
d="m 212,163 h 58" d="m 212,163 h 58"
style="fill:none;" /> style="fill:none;" />
<path <path
id="path978" id="path978"
d="M 32,140 H 2 v 61 H 32 Z" d="M 32,140 H 2 v 61 H 32 Z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path980" id="path980"
d="M 99,121 H 9 v 18" d="M 99,121 H 9 v 18"
style="fill:none;" /> style="fill:none;" />
<path <path
id="path982" id="path982"
d="M 33,175 H 98" d="M 33,175 H 98"
style="fill:none;" /> style="fill:none;" />
<path <path
id="path984" id="path984"
d="m 8,201 v 21 H 98" d="m 8,201 v 21 H 98"
style="fill:none;" /> style="fill:none;" />
<path <path
id="fbVLtube" id="fbVLtube"
d="m 99,164 h 7 V 244 H 8 v 23" d="m 99,164 h 7 V 244 H 8 v 23"
style="fill:none;" /> style="fill:none;" />
<path <path
id="fbRLtube" id="fbRLtube"
d="m 8,302 v 32 H 107 v -79 h -9" d="m 8,302 v 32 H 107 v -79 h -9"
style="fill:none;" /> style="fill:none;" />
<path <path
id="path990" id="path990"
d="m 211,112 h 39 V 68" d="m 211,112 h 39 V 68"
style="fill:none;" /> style="fill:none;" />
<path <path
id="path992" id="path992"
d="M 26,151 H 8 v 2 H 6 v 4 l -1,1 v 30 H 28 v -34 l -1,-1 v -4 z" d="M 26,151 H 8 v 2 H 6 v 4 l -1,1 v 30 H 28 v -34 l -1,-1 v -4 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path994" id="path994"
d="M 28,167 H 5" d="M 28,167 H 5"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path996" id="path996"
d="M 5,161 H 28" d="M 5,161 H 28"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path998" id="path998"
d="M 27,156 H 7" d="M 27,156 H 7"
style="fill:none;stroke-width:1px;s" /> style="fill:none;stroke-width:1px;s" />
<path <path
id="path1000" id="path1000"
d="m 10,152 1,2 H 24 l 1,-2 z" d="m 10,152 1,2 H 24 l 1,-2 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1002" id="path1002"
d="m 24,167 v 5 h 4" d="m 24,167 v 5 h 4"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1004" id="path1004"
d="M 47,268 H 1 v 34 H 47 v -34 z" d="M 47,268 H 1 v 34 H 47 v -34 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1006" id="path1006"
d="m 8,269 v 2 c 0,0 -1,0 -1,1 0,1 1,1 1,1 H 40 c 0,0 1,0 1,1 0,1 -1,1 -1,1 H 8 c 0,0 -1,0 -1,1 0,1 1,1 1,1 H 40 c 0,0 1,0 1,1 0,1 -1,1 -1,1 H 8 c 0,0 -1,0 -1,1 0,1 1,1 1,1 H 40 c 0,0 1,0 1,1 0,1 -1,1 -1,1 H 8 c 0,0 -1,0 -1,1 0,1 1,1 1,1 H 40 c 0,0 1,0 1,1 0,1 -1,1 -1,1 H 8 c 0,0 -1,0 -1,1 -0,1 1,1 1,1 h 31 c 0,0 1,0 1,1 0,1 -1,1 -1,1 H 8 v 4" d="m 8,269 v 2 c 0,0 -1,0 -1,1 0,1 1,1 1,1 H 40 c 0,0 1,0 1,1 0,1 -1,1 -1,1 H 8 c 0,0 -1,0 -1,1 0,1 1,1 1,1 H 40 c 0,0 1,0 1,1 0,1 -1,1 -1,1 H 8 c 0,0 -1,0 -1,1 0,1 1,1 1,1 H 40 c 0,0 1,0 1,1 0,1 -1,1 -1,1 H 8 c 0,0 -1,0 -1,1 0,1 1,1 1,1 H 40 c 0,0 1,0 1,1 0,1 -1,1 -1,1 H 8 c 0,0 -1,0 -1,1 -0,1 1,1 1,1 h 31 c 0,0 1,0 1,1 0,1 -1,1 -1,1 H 8 v 4"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1008" id="path1008"
d="M 294,238 Z" d="M 294,238 Z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="heizerRLtube2" id="heizerRLtube2"
d="m 295,238 h 10" d="m 295,238 h 10"
style="fill:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> style="fill:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path <path
id="path1012" id="path1012"
d="M 270,163 Z" d="M 270,163 Z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="heizregler" id="heizregler"
d="m 282,247 v 7 c 0,0 0,4 7,4 6,0 7,-4 7,-4 v -7 c 0,0 -0,3 -8,3 -7,0 -6,-3 -6,-3 z" d="m 282,247 v 7 c 0,0 0,4 7,4 6,0 7,-4 7,-4 v -7 c 0,0 -0,3 -8,3 -7,0 -6,-3 -6,-3 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="Heizstab" id="Heizstab"
d="m 293,246 v -74 c 0,0 -0,-2 -4,-2 -4,0 -4,2 -4,2 v 74 c 0,0 -0,1 4,1 4,-0 4,-1 4,-1 z" d="m 293,246 v -74 c 0,0 -0,-2 -4,-2 -4,0 -4,2 -4,2 v 74 c 0,0 -0,1 4,1 4,-0 4,-1 4,-1 z"
style="fill:#212529;stroke-width:1px;" /> style="fill:#212529;stroke-width:1px;" />
<path <path
id="path1020" id="path1020"
d="m 270,163 h 19 v 5" d="m 270,163 h 19 v 5"
style="fill:none;" /> style="fill:none;" />
<path <path
id="path1022" id="path1022"
d="m 282,247 c 0,0 -0,-2 2,-2" d="m 282,247 c 0,0 -0,-2 2,-2"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1024" id="path1024"
d="m 296,247 c 0,0 0,-2 -3,-3" d="m 296,247 c 0,0 0,-2 -3,-3"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path976-2" id="path976-2"
d="m 213,332 h 75" d="m 213,332 h 75"
style="fill:none;stroke-width:4;" /> style="fill:none;stroke-width:4;" />
<path <path
id="path1043" id="path1043"
d="m 240,338 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z" d="m 240,338 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1043-9" id="path1043-9"
d="m 240,169 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z" d="m 240,169 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1043-5" id="path1043-5"
d="m 65,228 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z" d="m 65,228 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1043-3" id="path1043-3"
d="m 65,250 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z" d="m 65,250 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1043-94" id="path1043-94"
d="m 253,288 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z" d="m 253,288 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1043-94-5" id="path1043-94-5"
d="m 236,103 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z" d="m 236,103 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1043-94-2" id="path1043-94-2"
d="m 65,342 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z" d="m 65,342 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1043-94-6" id="path1043-94-6"
d="m 65,126 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z" d="m 65,126 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1043-94-9" id="path1043-94-9"
d="m 65,180 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z" d="m 65,180 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1123" id="path1123"
d="m 253,52 h 9 c 0,0 3,-0 5,1 1,1 1,5 1,5 l -0,3 c 0,0 2,0 3,1 1,1 1,3 1,3 h -11 c 0,0 -0,-2 1,-4 1,-1 2,-1 2,-1 v -3 c 0,0 0,-2 -1,-3 -1,-0 -2,-0 -2,-0 h -9" d="m 253,52 h 9 c 0,0 3,-0 5,1 1,1 1,5 1,5 l -0,3 c 0,0 2,0 3,1 1,1 1,3 1,3 h -11 c 0,0 -0,-2 1,-4 1,-1 2,-1 2,-1 v -3 c 0,0 0,-2 -1,-3 -1,-0 -2,-0 -2,-0 h -9"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1125" id="path1125"
d="m 266,68 -0,2" d="m 266,68 -0,2"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1127" id="path1127"
d="m 266,73 v 1" d="m 266,73 v 1"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1129" id="path1129"
d="m 268,68 v 2" d="m 268,68 v 2"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1131" id="path1131"
d="m 268,73 v 1" d="m 268,73 v 1"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1133" id="path1133"
d="m 271,69 v 2" d="m 271,69 v 2"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1135" id="path1135"
d="M 271,74 V 75" d="M 271,74 V 75"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1137" id="path1137"
d="m 285,314 h -4 v 12 h 4" d="m 285,314 h -4 v 12 h 4"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1139" id="path1139"
d="m 280,318 h -4 v -5 h -4 v 5 h -4 c 0,0 -1,-0 -2,1 -0,1 -0,4 -0,4 0,0 -0,3 2,3 2,0 2,-2 2,-3 0,-1 2,-1 2,-1 l 9,0" d="m 280,318 h -4 v -5 h -4 v 5 h -4 c 0,0 -1,-0 -2,1 -0,1 -0,4 -0,4 0,0 -0,3 2,3 2,0 2,-2 2,-3 0,-1 2,-1 2,-1 l 9,0"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
<path <path
id="path1141" id="path1141"
d="m 278,312 h -9 c -1,0 -2,-1 0,-1 2,0 2,1 4,1 2,0 3,-1 5,-1 2,0 0,1 -0,1 z" d="m 278,312 h -9 c -1,0 -2,-1 0,-1 2,0 2,1 4,1 2,0 3,-1 5,-1 2,0 0,1 -0,1 z"
style="fill:none;stroke-width:1px;" /> style="fill:none;stroke-width:1px;" />
</g> </g>
<g style="font-size: 28px; font-weight: 600; font-family: sans-serif; text-anchor: middle; fill: rgb(200, 210, 210); letter-spacing: 1px;" > <g style="font-size: 28px; font-weight: 600; font-family: sans-serif; text-anchor: middle; fill: rgb(200, 210, 210); letter-spacing: 1px;" >
<text id="PufferOtxt" dy="200" dx="320"> <text id="PufferOtxt" dy="200" dx="320">
--.- °C --.- °C
</text> </text>
<text id="PufferMtxt" dy="400" dx="320"> <text id="PufferMtxt" dy="400" dx="320">
--.- °C --.- °C
</text> </text>
<text id="PufferUtxt" dy="600" dx="320"> <text id="PufferUtxt" dy="600" dx="320">
--.- °C --.- °C
</text> </text>
<text id="heaterRL" dy="505" dx="530" style="font-size: 22px;"> <text id="heaterRL" dy="505" dx="530" style="font-size: 22px;">
--.- °C --.- °C
</text> </text>
<text id="heaterVL" dy="260" dx="530" style="font-size: 22px;"> <text id="heaterVL" dy="260" dx="530" style="font-size: 22px;">
--.- °C --.- °C
</text> </text>
<text id="fbVL" dy="465" dx="70" style="font-size: 22px;"> <text id="fbVL" dy="465" dx="70" style="font-size: 22px;">
--.- °C --.- °C
</text> </text>
<text id="fbRL" dy="605" dx="70" style="font-size: 22px;"> <text id="fbRL" dy="605" dx="70" style="font-size: 22px;">
--.- °C --.- °C
</text> </text>
<text id="thermeRL" dy="385" dx="70" style="font-size: 22px;"> <text id="thermeRL" dy="385" dx="70" style="font-size: 22px;">
--.- °C --.- °C
</text> </text>
<text id="thermeVLfb" dy="290" dx="110" style="font-size: 22px;"> <text id="thermeVLfb" dy="290" dx="110" style="font-size: 22px;">
--.- °C --.- °C
</text> </text>
<text id="thermeVLww" dy="180" dx="70" style="font-size: 22px;"> <text id="thermeVLww" dy="180" dx="70" style="font-size: 22px;">
--.- °C --.- °C
</text> </text>
<text id="triacLbl" dy="350" dx="515" style="font-size: 22px;"> <text id="triacLbl" dy="350" dx="515" style="font-size: 22px;">
Triac: Triac:
</text> </text>
<text id="triac" dy="375" dx="515" style="font-size: 22px;"> <text id="triac" dy="375" dx="515" style="font-size: 22px;">
--.- °C --.- °C
</text> </text>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -1,475 +1,475 @@
<svg xmlns="http://www.w3.org/2000/svg" <svg xmlns="http://www.w3.org/2000/svg"
viewBox="-100 -100 1600 950" width="100%" height="100%" id="realtimeSvgAni"> viewBox="-100 -100 1600 950" width="100%" height="100%" id="realtimeSvgAni">
<defs> <defs>
<filter id="shadow" x="-0.5" y="-0.5" width="200%" height="200%"> <filter id="shadow" x="-0.5" y="-0.5" width="200%" height="200%">
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" /> <feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
<feMorphology in="offOut" 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="-1.0" y="-1.0" width="300%" height="300%">
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" /> <feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
<feMorphology in="offOut" 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="-1" y="-1" width="300%" height="300%">
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" /> <feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
<feMorphology in="offOut" 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>
<g id="circGrid"> <g id="circGrid">
<line x2='27.7' y2='76.5' x1='-18.9' y1='61.4' style='stroke-width:4px' /> <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='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='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='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='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='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='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='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='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='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' /> <line x2='100' y2='24' x1='100' y1='-24' style='stroke-width:4px' />
</g> </g>
<g id="circGrid6kW"> <g id="circGrid6kW">
<line x2='27.7' y2='76.5' x1='-18.9' y1='61.4' style='stroke-width:4px' /> <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='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='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='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='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='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' /> <line x2='100' y2='24' x1='100' y1='-24' style='stroke-width:4px' />
</g> </g>
<linearGradient id="gradient1" x1="0" x2="0" y1="0" y2="1"> <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="tmpH" offset="0%" stop-color="#2389BA" stop-opacity="0.7" />
<stop id="tmpM" offset="50%" 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" /> <stop id="tmpL" offset="100%" stop-color="#2389BA" stop-opacity="0.7" />
</linearGradient> </linearGradient>
<filter id="fillpartialEV" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" <filter id="fillpartialEV" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%"> height="110%">
<feFlood flood-color="#1f5a66" /> <feFlood flood-color="#1f5a66" />
<feComposite id="evChargeState" y="100%" operator="in" in2="SourceGraphic" /> <feComposite id="evChargeState" y="100%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" /> <feComposite operator="over" in2="SourceGraphic" />
</filter> </filter>
<filter id="fillpartialHeat" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" <filter id="fillpartialHeat" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%"> height="110%">
<feFlood flood-color="#5E2B21" /> <feFlood flood-color="#5E2B21" />
<feComposite id="heatChargeState" y="100%" operator="in" in2="SourceGraphic" /> <feComposite id="heatChargeState" y="100%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" /> <feComposite operator="over" in2="SourceGraphic" />
</filter> </filter>
<filter id="fillpartialBat" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" <filter id="fillpartialBat" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%"> height="110%">
<feFlood flood-color="#25481C" /> <feFlood flood-color="#25481C" />
<feComposite id="batChargeState" y="100%" operator="in" in2="SourceGraphic" /> <feComposite id="batChargeState" y="100%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" /> <feComposite operator="over" in2="SourceGraphic" />
</filter> </filter>
<filter id="fillpartialWater" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" <filter id="fillpartialWater" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%"> height="110%">
<feFlood flood-color="#182C43" /> <feFlood flood-color="#182C43" />
<feComposite id="waterState" y="50%" operator="in" in2="SourceGraphic" /> <feComposite id="waterState" y="50%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" /> <feComposite operator="over" in2="SourceGraphic" />
</filter> </filter>
<g id="heater" transform="rotate(-90),scale(0.07,0.07)"> <g id="heater" transform="rotate(-90),scale(0.07,0.07)">
<path <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 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 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.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 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 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 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 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 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,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-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 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 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 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 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 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 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 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 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 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 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 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 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" /> v17.39c0,4.78-3.915,8.661-8.72,8.661H468.61v-34.712H485.924z" />
</g> </g>
<g id="gas"> <g id="gas">
<path fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" <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 " /> 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>
<g id="water"> <g id="water">
<path <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 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 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 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 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 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 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" /> C222.575,351.396,220.761,353.729,218.171,354.342z" />
</g> </g>
<g id="voltage"> <g id="voltage">
<path stroke="#212529" stroke-width="0.2px" d="M11.46,18V13.58H9.86L12.54,8v3.89h1.6Z" /> <path stroke="#212529" stroke-width="0.2px" d="M11.46,18V13.58H9.86L12.54,8v3.89h1.6Z" />
</g> </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="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> <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"> <g id="pvPlate" fill="none" stroke-width="4" stroke="#f7c000">
<rect width="70" height="40" x="0" y="0" rx="5" ry="5" /> <rect width="70" height="40" x="0" y="0" rx="5" ry="5" />
</g> </g>
<g id="ElementBG"> <g id="ElementBG">
<path fill="#212529" stroke-width="1.5" <path fill="#212529" stroke-width="1.5"
d="M 99.80277789465349 -12.999827891201505 A 113 113 0 1 0 100 -13" /> d="M 99.80277789465349 -12.999827891201505 A 113 113 0 1 0 100 -13" />
<path fill="none" stroke-width="4" <path fill="none" stroke-width="4"
d="M 99.86386438745993 22.00011880076356 A 78 78 0 1 0 100 22" /> d="M 99.86386438745993 22.00011880076356 A 78 78 0 1 0 100 22" />
</g> </g>
<g id="plugIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)" fill="#71afcd"> <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="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="M10.39,6.73V2.62A.7.7,0,0,0,9.6,2h0a.73.73,0,0,0-.78.66V6.73Z" />
<path <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" /> 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>
<g id="ogIcon" filter="url(#shadow)" transform="translate(52,45),scale(4,4)"> <g id="ogIcon" filter="url(#shadow)" transform="translate(52,45),scale(4,4)">
<polygon fill="#70CCBB" <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" /> 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" <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" /> 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="M10.76,11.41v-1.3c0-.45-.17-.67-.52-.68s-.54.22-.54.69v1.67h1.06Z" />
<path fill="#70CCBB" <path fill="#70CCBB"
d="M14.3,11.41c0-.44,0-.88,0-1.3s-.17-.67-.51-.68-.55.22-.55.69v1.67H14.3Z" /> d="M14.3,11.41c0-.44,0-.88,0-1.3s-.17-.67-.51-.68-.55.22-.55.69v1.67H14.3Z" />
<path fill="#212529" <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" /> 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>
<g id="heatIcon" filter="url(#shadow)" transform="translate(52,70),scale(4,4)" fill="#C2614E"> <g id="heatIcon" filter="url(#shadow)" transform="translate(52,70),scale(4,4)" fill="#C2614E">
<path clip-path="M-22 2.24h42V22h-42z" <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" /> 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>
<g id="ugIcon" filter="url(#shadow)" transform="translate(52,50),scale(4,4)"> <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" /> <rect stroke="#70CC9C" stroke-width="2" fill="none" x="3" y="3" width="18" height="18" rx="2" />
<path fill="#70CC9C" <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" /> 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="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="#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" <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" /> 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>
<g id="carIcon" filter="url(#shadow)" transform="translate(45,45),scale(4.8,4.8)" <g id="carIcon" filter="url(#shadow)" transform="translate(45,45),scale(4.8,4.8)"
fill="#212529" stroke-linecap="round"> 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="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 <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" /> 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" <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" /> 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="4.94" cy="15.08" r="1.98" />
<circle cx="19.19" cy="15.08" r="1.98" /> <circle cx="19.19" cy="15.08" r="1.98" />
</g> </g>
<g id="plugCordIcon" transform="scale(0.08,0.08),rotate(340),translate(-350,1200)"> <g id="plugCordIcon" transform="scale(0.08,0.08),rotate(340),translate(-350,1200)">
<path <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 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 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 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 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" /> 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>
<g id="lockIcon" transform="translate(80,130),scale(0.11,0.11)" style=""> <g id="lockIcon" transform="translate(80,130),scale(0.11,0.11)" style="">
<path <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 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 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 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 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" 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;" /> style="stroke-width:15px;stroke:rgb(30,30,40);fill:#778;" />
</g> </g>
<g filter="url(#shadow)" id="clock" style="fill:#cc0;" <g filter="url(#shadow)" id="clock" style="fill:#cc0;"
transform="translate(80,32),scale(0.07,0.07)"> transform="translate(80,32),scale(0.07,0.07)">
<path <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" /> 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 <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" /> 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>
<g id="sunIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)" <g id="sunIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)"
style="stroke:#f7c000;stroke-width:2;stroke-linecap:round;"> style="stroke:#f7c000;stroke-width:2;stroke-linecap:round;">
<path id="Pfad_7565" data-name="Pfad 7565" fill="#f7c002" stroke-width="0" <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" /> 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="3" x2="12" y2="5" />
<line x1="12" y1="19" x2="12" y2="21" /> <line x1="12" y1="19" x2="12" y2="21" />
<line x1="19" y1="12" x2="21" y2="12" /> <line x1="19" y1="12" x2="21" y2="12" />
<line x1="3" y1="12" x2="5" 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="18.5" x2="7" y2="17" />
<line x1="5.7" y1="5.7" x2="7" y2="7" /> <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="18.5" x2="16.7" y2="17" />
<line x1="18.5" y1="5.7" x2="16.7" y2="7" /> <line x1="18.5" y1="5.7" x2="16.7" y2="7" />
</g> </g>
<g id="battIcon" filter="url(#shadow)" transform="translate(30,25),scale(6,6)"> <g id="battIcon" filter="url(#shadow)" transform="translate(30,25),scale(6,6)">
<g> <g>
<rect fill="#6cbe58" x="9.25" y="3" width="5.5" height="4" rx="1" ry="1" /> <rect fill="#6cbe58" x="9.25" y="3" width="5.5" height="4" rx="1" ry="1" />
<path fill="#6cbe58" <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" /> 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" <rect id="discharged" fill="#212529" rx="1" ry="1" x="8" y="6.5" width="8"
height="13" /> height="13" />
<use id="charge" fill="#cccc00" href="#voltage" /> <use id="charge" fill="#cccc00" href="#voltage" />
</g> </g>
</g> </g>
<g id="gridIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)"> <g id="gridIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)">
<path fill="#808090" <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" /> 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>
<g id="inverterIcon" filter="url(#shadowBig)" fill="#b2b2b2" stroke-width="2px" stroke="#666" <g id="inverterIcon" filter="url(#shadowBig)" fill="#b2b2b2" stroke-width="2px" stroke="#666"
transform="translate(43,43),scale(1.6,1.6)"> 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" /> <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="35.03" cy="29.61" r="11" />
<circle cx="15" cy="40" r="4" /> <circle cx="15" cy="40" r="4" />
<path <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" /> 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" <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" /> 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="5.07" y1="53.08" x2="28.73" y2="53.08" />
<line x1="41.27" y1="53.08" x2="64.93" y2="53.08" /> <line x1="41.27" y1="53.08" x2="64.93" y2="53.08" />
</g> </g>
<g id="northIcon" fill="#808090"> <g id="northIcon" fill="#808090">
<path <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> 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>
<g filter="url(#shadow)" id="ecoIcon" transform="translate(60,12)"> <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" <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 " /> 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>
<g filter="url(#shadow)" id="alertIcon" fill="#aa0" transform="translate(34,28),scale(2.2,2.2)"> <g filter="url(#shadow)" id="alertIcon" fill="#aa0" transform="translate(34,28),scale(2.2,2.2)">
<path <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" 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)" /> id="attention" transform="translate(-209.969 -694)" />
</g> </g>
</defs> </defs>
<g id="pvDetail" opacity="1" transform="scale(1,1)"> <g id="pvDetail" opacity="1" transform="scale(1,1)">
<g id="pvInfo" transform="translate(80,30)" class="clickable" onclick="displayOverlay('realtime')"> <g id="pvInfo" transform="translate(80,30)" class="clickable" onclick="displayOverlay('realtime')">
<!--<g <!--<g
filter="url(#glow)">--> filter="url(#glow)">-->
<use href="#ElementBG" stroke="#574400" /> <use href="#ElementBG" stroke="#574400" />
<use href="#sunIcon" /> <use href="#sunIcon" />
<path id="pvArc" fill="none" stroke="#f7c000" stroke-width="30" /> <path id="pvArc" fill="none" stroke="#f7c000" stroke-width="30" />
<path id="pv2Arc" fill="none" stroke="#f78d00" stroke-width="30" /> <path id="pv2Arc" fill="none" stroke="#f78d00" stroke-width="30" />
<path id="pv3Arc" fill="none" stroke="#f72300" stroke-width="30" /> <path id="pv3Arc" fill="none" stroke="#f72300" stroke-width="30" />
<use href="#circGrid" style="stroke:#574400;" /> <use href="#circGrid" style="stroke:#574400;" />
<!--</g>--> <!--</g>-->
<text filter="url(#shadowMiddle)" class="powerTextClass"> <text filter="url(#shadowMiddle)" class="powerTextClass">
<textPath id="pvText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath> <textPath id="pvText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
<textPath id="pv3txt" href="#infoTextPath" startOffset="12%">--.-- kW</textPath> <textPath id="pv3txt" href="#infoTextPath" startOffset="12%">--.-- kW</textPath>
<textPath id="pv2txt" href="#infoTextPath" startOffset="35%">--.-- kW</textPath> <textPath id="pv2txt" href="#infoTextPath" startOffset="35%">--.-- kW</textPath>
<textPath id="pv1txt" href="#infoTextPath" startOffset="55%">--W</textPath> <textPath id="pv1txt" href="#infoTextPath" startOffset="55%">--W</textPath>
</text> </text>
</g> </g>
<animate begin="openDetails.begin" attributetype="CSS" attributeName="opacity" from="0" <animate begin="openDetails.begin" attributetype="CSS" attributeName="opacity" from="0"
to="1.0" to="1.0"
dur="0.7s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" dur="0.7s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze" /> fill="freeze" />
<animateTransform attributeName="transform" <animateTransform attributeName="transform"
type="scale" type="scale"
from="0.1,0.1" from="0.1,0.1"
to="1,1" to="1,1"
begin="openDetails.begin" begin="openDetails.begin"
dur="0.3s" repeatCount="1" fill="freeze" /> dur="0.3s" repeatCount="1" fill="freeze" />
<animate begin="closeDetails.click" attributetype="CSS" attributeName="opacity" from="1.0" <animate begin="closeDetails.click" attributetype="CSS" attributeName="opacity" from="1.0"
to="0" to="0"
dur="0.4s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" dur="0.4s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze" /> fill="freeze" />
<animateTransform attributeName="transform" <animateTransform attributeName="transform"
type="scale" type="scale"
from="1,1" from="1,1"
to="0.1,0.1" to="0.1,0.1"
begin="closeDetails.click" begin="closeDetails.click"
dur="0.7s" repeatCount="1" fill="freeze" /> dur="0.7s" repeatCount="1" fill="freeze" />
<use href="#northIcon" transform="translate(1200,10),rotate(10)" /> <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="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" <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" /> 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,80), rotate(90)" />
<use href="#pvPlate" transform="translate(600,150), 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,220), rotate(90)" />
<use href="#pvPlate" transform="translate(600,290), 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,80), rotate(90)" />
<use href="#pvPlate" transform="translate(640,150), 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,220), rotate(90)" />
<use href="#pvPlate" transform="translate(640,290), 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,80), rotate(90)" />
<use href="#pvPlate" transform="translate(680,150), 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,220), rotate(90)" />
<use href="#pvPlate" transform="translate(680,290), 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,80), rotate(90)" />
<use href="#pvPlate" transform="translate(720,150), 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(720,220), rotate(90)" />
<use href="#pvPlate" transform="translate(790,290)" /> <use href="#pvPlate" transform="translate(790,290)" />
<use href="#pvPlate" transform="translate(720,330)" /> <use href="#pvPlate" transform="translate(720,330)" />
<use href="#pvPlate" transform="translate(790,330)" /> <use href="#pvPlate" transform="translate(790,330)" />
<use href="#pvPlate" transform="translate(870,290)" /> <use href="#pvPlate" transform="translate(870,290)" />
<use href="#pvPlate" transform="translate(870,330)" /> <use href="#pvPlate" transform="translate(870,330)" />
<use href="#pvPlate" transform="translate(940,330)" /> <use href="#pvPlate" transform="translate(940,330)" />
<use href="#pvPlate" transform="translate(1160,300), rotate(90)" /> <use href="#pvPlate" transform="translate(1160,300), rotate(90)" />
<use href="#pvPlate" transform="translate(1120,300), rotate(90)" /> <use href="#pvPlate" transform="translate(1120,300), rotate(90)" />
<use href="#pvPlate" transform="translate(1080,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" <text id="det_pv0P" filter="url(#shadowBig)" class="infoTextClass" dx="55" dy="30"
transform="translate(560, 150), scale(1.5,1.5)">-.-- kW</text> 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" <polygon points="980,60 1160,60 1160,265 980,265" stroke-linejoin="round" fill="#F76D00"
stroke-width="30" stroke="#F76D00" opacity="0.1" /> 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(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(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(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(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(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(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(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(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(1115,60), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1070,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" <text id="det_pv1P" filter="url(#shadowBig)" class="infoTextClass" dx="55" dy="30"
transform="translate(990, 140), scale(1.5,1.5)">-.-- kW</text> transform="translate(990, 140), scale(1.5,1.5)">-.-- kW</text>
<use href="#pvPlate" x="200" y="680" /> <use href="#pvPlate" x="200" y="680" />
<text id="det_pv33P" filter="url(#shadowMiddle)" class="infoTextClass" x="200" y="680" <text id="det_pv33P" filter="url(#shadowMiddle)" class="infoTextClass" x="200" y="680"
dx="36" dx="36"
dy="26">#19</text> dy="26">#19</text>
<use href="#pvPlate" x="380" y="550" /> <use href="#pvPlate" x="380" y="550" />
<text id="det_pv32P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="550" <text id="det_pv32P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="550"
dx="36" dx="36"
dy="26">#19</text> dy="26">#19</text>
<use href="#pvPlate" x="380" y="590" /> <use href="#pvPlate" x="380" y="590" />
<text id="det_pv31P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="590" <text id="det_pv31P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="590"
dx="36" dx="36"
dy="26">#18</text> dy="26">#18</text>
<use href="#pvPlate" x="380" y="630" /> <use href="#pvPlate" x="380" y="630" />
<text id="det_pv30P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="630" <text id="det_pv30P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="630"
dx="36" dx="36"
dy="26">#17</text> dy="26">#17</text>
<use href="#pvPlate" x="310" y="510" /> <use href="#pvPlate" x="310" y="510" />
<text id="det_pv29P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="510" <text id="det_pv29P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="510"
dx="36" dx="36"
dy="26">#16</text> dy="26">#16</text>
<use href="#pvPlate" x="310" y="550" /> <use href="#pvPlate" x="310" y="550" />
<text id="det_pv28P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="550" <text id="det_pv28P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="550"
dx="36" dx="36"
dy="26">#15</text> dy="26">#15</text>
<use href="#pvPlate" x="310" y="590" /> <use href="#pvPlate" x="310" y="590" />
<text id="det_pv27P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="590" <text id="det_pv27P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="590"
dx="36" dx="36"
dy="26">#14</text> dy="26">#14</text>
<use href="#pvPlate" x="310" y="630" /> <use href="#pvPlate" x="310" y="630" />
<text id="det_pv26P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="630" <text id="det_pv26P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="630"
dx="36" dx="36"
dy="26">#13</text> dy="26">#13</text>
<use href="#pvPlate" x="240" y="510" /> <use href="#pvPlate" x="240" y="510" />
<text id="det_pv25P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="510" <text id="det_pv25P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="510"
dx="36" dx="36"
dy="26">#12</text> dy="26">#12</text>
<use href="#pvPlate" x="240" y="550" /> <use href="#pvPlate" x="240" y="550" />
<text id="det_pv24P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="550" <text id="det_pv24P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="550"
dx="36" dx="36"
dy="26">#11</text> dy="26">#11</text>
<use href="#pvPlate" x="240" y="590" /> <use href="#pvPlate" x="240" y="590" />
<text id="det_pv23P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="590" <text id="det_pv23P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="590"
dx="36" dx="36"
dy="26">#10</text> dy="26">#10</text>
<use href="#pvPlate" x="240" y="630" /> <use href="#pvPlate" x="240" y="630" />
<text id="det_pv22P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="630" <text id="det_pv22P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="630"
dx="36" dx="36"
dy="26">#9</text> dy="26">#9</text>
<use href="#pvPlate" x="170" y="510" /> <use href="#pvPlate" x="170" y="510" />
<text id="det_pv21P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="510" <text id="det_pv21P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="510"
dx="36" dx="36"
dy="26">#8</text> dy="26">#8</text>
<use href="#pvPlate" x="170" y="550" /> <use href="#pvPlate" x="170" y="550" />
<text id="det_pv20P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="550" <text id="det_pv20P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="550"
dx="36" dx="36"
dy="26">#7</text> dy="26">#7</text>
<use href="#pvPlate" x="170" y="590" /> <use href="#pvPlate" x="170" y="590" />
<text id="det_pv19P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="590" <text id="det_pv19P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="590"
dx="36" dx="36"
dy="26">#6</text> dy="26">#6</text>
<use href="#pvPlate" x="170" y="630" /> <use href="#pvPlate" x="170" y="630" />
<text id="det_pv18P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="630" <text id="det_pv18P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="630"
dx="36" dx="36"
dy="26">#5</text> dy="26">#5</text>
<use href="#pvPlate" x="100" y="510" /> <use href="#pvPlate" x="100" y="510" />
<text id="det_pv14P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="510" <text id="det_pv14P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="510"
dx="36" dx="36"
dy="26">#1</text> dy="26">#1</text>
<use href="#pvPlate" x="100" y="550" /> <use href="#pvPlate" x="100" y="550" />
<text id="det_pv15P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="550" <text id="det_pv15P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="550"
dx="36" dx="36"
dy="26">#2</text> dy="26">#2</text>
<use href="#pvPlate" x="100" y="590" /> <use href="#pvPlate" x="100" y="590" />
<text id="det_pv16P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="590" <text id="det_pv16P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="590"
dx="36" dx="36"
dy="26">#3</text> dy="26">#3</text>
<use href="#pvPlate" x="100" y="630" /> <use href="#pvPlate" x="100" y="630" />
<text id="det_pv17P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="630" <text id="det_pv17P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="630"
dx="36" dx="36"
dy="26">#4</text> dy="26">#4</text>
<use href="#pvPlate" transform="translate(600,500)" /> <use href="#pvPlate" transform="translate(600,500)" />
<text id="det_pv13P" filter="url(#shadowMiddle)" class="infoTextClass" x="600" y="500" <text id="det_pv13P" filter="url(#shadowMiddle)" class="infoTextClass" x="600" y="500"
dx="36" dx="36"
dy="26">- W</text> dy="26">- W</text>
<use href="#pvPlate" transform="translate(500,500)" /> <use href="#pvPlate" transform="translate(500,500)" />
<text id="det_pv12P" filter="url(#shadowMiddle)" class="infoTextClass" x="500" y="500" <text id="det_pv12P" filter="url(#shadowMiddle)" class="infoTextClass" x="500" y="500"
dx="36" dx="36"
dy="26">- W</text> dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,120), rotate(-90)" /> <use href="#pvPlate" transform="translate(460,120), rotate(-90)" />
<text id="det_pv5P" filter="url(#shadowMiddle)" class="infoTextClass" <text id="det_pv5P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,120), rotate(-90)" dx="36" dy="26">- W</text> transform="translate(460,120), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,190), rotate(-90)" /> <use href="#pvPlate" transform="translate(460,190), rotate(-90)" />
<text id="det_pv4P" filter="url(#shadowMiddle)" class="infoTextClass" <text id="det_pv4P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,190), rotate(-90)" dx="36" dy="26">- W</text> transform="translate(460,190), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,270), rotate(-90)" /> <use href="#pvPlate" transform="translate(460,270), rotate(-90)" />
<text id="det_pv9P" filter="url(#shadowMiddle)" class="infoTextClass" <text id="det_pv9P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,270), rotate(-90)" dx="36" dy="26">- W</text> transform="translate(460,270), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,340), rotate(-90)" /> <use href="#pvPlate" transform="translate(460,340), rotate(-90)" />
<text id="det_pv8P" filter="url(#shadowMiddle)" class="infoTextClass" <text id="det_pv8P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,340), rotate(-90)" dx="36" dy="26">- W</text> transform="translate(460,340), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,420), rotate(-90)" /> <use href="#pvPlate" transform="translate(460,420), rotate(-90)" />
<text id="det_pv11P" filter="url(#shadowMiddle)" class="infoTextClass" <text id="det_pv11P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,420), rotate(-90)" dx="36" dy="26">- W</text> transform="translate(460,420), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,490), rotate(-90)" /> <use href="#pvPlate" transform="translate(460,490), rotate(-90)" />
<text id="det_pv10P" filter="url(#shadowMiddle)" class="infoTextClass" <text id="det_pv10P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,490), rotate(-90)" dx="36" dy="26">- W</text> transform="translate(460,490), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,120), rotate(-90)" /> <use href="#pvPlate" transform="translate(400,120), rotate(-90)" />
<text id="det_pv7P" filter="url(#shadowMiddle)" class="infoTextClass" <text id="det_pv7P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,120), rotate(-90)" dx="36" dy="26">- W</text> transform="translate(400,120), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,190), rotate(-90)" /> <use href="#pvPlate" transform="translate(400,190), rotate(-90)" />
<text id="det_pv6P" filter="url(#shadowMiddle)" class="infoTextClass" <text id="det_pv6P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,190), rotate(-90)" dx="36" dy="26">- W</text> transform="translate(400,190), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,270), rotate(-90)" /> <use href="#pvPlate" transform="translate(400,270), rotate(-90)" />
<text id="det_pv3P" filter="url(#shadowMiddle)" class="infoTextClass" <text id="det_pv3P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,270), rotate(-90)" dx="36" dy="26">- W</text> transform="translate(400,270), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,340), rotate(-90)" /> <use href="#pvPlate" transform="translate(400,340), rotate(-90)" />
<text id="det_pv2P" filter="url(#shadowMiddle)" class="infoTextClass" <text id="det_pv2P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,340), rotate(-90)" dx="36" dy="26">- W</text> transform="translate(400,340), rotate(-90)" dx="36" dy="26">- W</text>
<text id="invList" filter="url(#shadowMiddle)" class="tooltipTextClass" <text id="invList" filter="url(#shadowMiddle)" class="tooltipTextClass"
transform="translate(80,255)"></text> transform="translate(80,255)"></text>
<rect width="305" height="210" x="70" y="250" rx="5" ry="5" fill="none" stroke-width="4px" <rect width="305" height="210" x="70" y="250" rx="5" ry="5" fill="none" stroke-width="4px"
stroke="#f7c000" /> stroke="#f7c000" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

File diff suppressed because it is too large Load Diff

View File

@ -1,354 +1,354 @@
<?php <?php
/* /*
* Copyright (C) 2022 Lukas Buchs * Copyright (C) 2022 Lukas Buchs
* license https://github.com/lbuchs/WebAuthn/blob/master/LICENSE MIT * license https://github.com/lbuchs/WebAuthn/blob/master/LICENSE MIT
* *
* Server test script for WebAuthn library. Saves new registrations in session. * Server test script for WebAuthn library. Saves new registrations in session.
* *
* JAVASCRIPT | SERVER * JAVASCRIPT | SERVER
* ------------------------------------------------------------ * ------------------------------------------------------------
* *
* REGISTRATION * REGISTRATION
* *
* window.fetch -----------------> getCreateArgs * window.fetch -----------------> getCreateArgs
* | * |
* navigator.credentials.create <-------------' * navigator.credentials.create <-------------'
* | * |
* '-------------------------> processCreate * '-------------------------> processCreate
* | * |
* alert ok or fail <----------------' * alert ok or fail <----------------'
* *
* ------------------------------------------------------------ * ------------------------------------------------------------
* *
* VALIDATION * VALIDATION
* *
* window.fetch ------------------> getGetArgs * window.fetch ------------------> getGetArgs
* | * |
* navigator.credentials.get <----------------' * navigator.credentials.get <----------------'
* | * |
* '-------------------------> processGet * '-------------------------> processGet
* | * |
* alert ok or fail <----------------' * alert ok or fail <----------------'
* *
* ------------------------------------------------------------ * ------------------------------------------------------------
*/ */
require_once './restricted/WebAuthn/src/WebAuthn.php'; require_once './restricted/WebAuthn/src/WebAuthn.php';
require_once("./restricted/mysql.php"); require_once("./restricted/mysql.php");
try { try {
session_start(); session_start();
// read get argument and post body // read get argument and post body
$fn = filter_input(INPUT_GET, 'fn'); $fn = filter_input(INPUT_GET, 'fn');
$requireResidentKey = false; $requireResidentKey = false;
$userVerification = false; $userVerification = false;
$formats = []; $formats = [];
$msg=""; $msg="";
$formats[] = 'android-key'; $formats[] = 'android-key';
$formats[] = 'android-safetynet'; $formats[] = 'android-safetynet';
$formats[] = 'apple'; $formats[] = 'apple';
$formats[] = 'fido-u2f'; $formats[] = 'fido-u2f';
$formats[] = 'none'; $formats[] = 'none';
$formats[] = 'packed'; $formats[] = 'packed';
$formats[] = 'tpm'; $formats[] = 'tpm';
$userId = "E071229F004A4CDE"; $userId = "E071229F004A4CDE";
$userName = "SmartHomeWagner"; $userName = "SmartHomeWagner";
$userDisplayName = "2025Bym0"; $userDisplayName = "2025Bym0";
$post = trim(file_get_contents('php://input')); $post = trim(file_get_contents('php://input'));
if ($post) { if ($post) {
$post = json_decode($post, null, 512, JSON_THROW_ON_ERROR); $post = json_decode($post, null, 512, JSON_THROW_ON_ERROR);
} }
$rpId = "nas.el-wa.org"; $rpId = "nas.el-wa.org";
if ($rpId === false) { if ($rpId === false) {
throw new Exception('invalid relying party ID'); throw new Exception('invalid relying party ID');
} }
// cross-platform: true, if type internal is not allowed // cross-platform: true, if type internal is not allowed
// false, if only internal is allowed // false, if only internal is allowed
// null, if internal and cross-platform is allowed // null, if internal and cross-platform is allowed
$crossPlatformAttachment = null; $crossPlatformAttachment = null;
// new Instance of the server library. // new Instance of the server library.
// make sure that $rpId is the domain name. // make sure that $rpId is the domain name.
$WebAuthn = new lbuchs\WebAuthn\WebAuthn('WebAuthn Library', $rpId, $formats); $WebAuthn = new lbuchs\WebAuthn\WebAuthn('WebAuthn Library', $rpId, $formats);
$WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/isrg-root-x2.pem'); $WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/isrg-root-x2.pem');
$WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/solo.pem'); $WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/solo.pem');
$WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/solokey_f1.pem'); $WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/solokey_f1.pem');
$WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/solokey_r1.pem'); $WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/solokey_r1.pem');
$WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/apple.pem'); $WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/apple.pem');
$WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/yubico.pem'); $WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/yubico.pem');
$WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/hypersecu.pem'); $WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/hypersecu.pem');
$WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/globalSign.pem'); $WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/globalSign.pem');
$WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/googleHardware.pem'); $WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/googleHardware.pem');
$WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/microsoftTpmCollection.pem'); $WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/microsoftTpmCollection.pem');
$WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/mds'); $WebAuthn->addRootCertificates('./restricted/WebAuthn/rootCertificates/mds');
// ------------------------------------ // ------------------------------------
// request for create arguments // request for create arguments
// ------------------------------------ // ------------------------------------
if ($fn === 'getCreateArgs') { if ($fn === 'getCreateArgs') {
$createArgs = $WebAuthn->getCreateArgs(\hex2bin($userId), $userName, $userDisplayName, 60*4, $requireResidentKey, $userVerification, $crossPlatformAttachment); $createArgs = $WebAuthn->getCreateArgs(\hex2bin($userId), $userName, $userDisplayName, 60*4, $requireResidentKey, $userVerification, $crossPlatformAttachment);
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($createArgs)); print(json_encode($createArgs));
// save challange to session. you have to deliver it to processGet later. // save challange to session. you have to deliver it to processGet later.
$_SESSION['challenge'] = $WebAuthn->getChallenge(); $_SESSION['challenge'] = $WebAuthn->getChallenge();
// ------------------------------------ // ------------------------------------
// request for get arguments // request for get arguments
// ------------------------------------ // ------------------------------------
} else if ($fn === 'getGetArgs') { } else if ($fn === 'getGetArgs') {
$ids = []; $ids = [];
$mysql = new mysqli($mysql_server,$mysql_user,$mysql_pass,$mysql_db); $mysql = new mysqli($mysql_server,$mysql_user,$mysql_pass,$mysql_db);
$result = mysqli_query($mysql,"SELECT credentialId FROM users WHERE userId = '".base64_encode($userId)."';"); $result = mysqli_query($mysql,"SELECT credentialId FROM users WHERE userId = '".base64_encode($userId)."';");
if(!$result){ if(!$result){
$msg = "Error:<br>".mysqli_error($mysql)."<br />"; $msg = "Error:<br>".mysqli_error($mysql)."<br />";
} }
if ($result->num_rows > 0) { if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) { while($row = $result->fetch_assoc()) {
$ids[] = base64_decode($row["credentialId"]); $ids[] = base64_decode($row["credentialId"]);
} }
} }
/* /*
if ($requireResidentKey) { if ($requireResidentKey) {
if (!isset($_SESSION['registrations']) || !is_array($_SESSION['registrations']) || count($_SESSION['registrations']) === 0) { if (!isset($_SESSION['registrations']) || !is_array($_SESSION['registrations']) || count($_SESSION['registrations']) === 0) {
throw new Exception('we do not have any registrations in session to check the registration'); throw new Exception('we do not have any registrations in session to check the registration');
} }
} else { } else {
// load registrations from session stored there by processCreate. // load registrations from session stored there by processCreate.
// normaly you have to load the credential Id's for a username // normaly you have to load the credential Id's for a username
// from the database. // from the database.
if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) { if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) {
foreach ($_SESSION['registrations'] as $reg) { foreach ($_SESSION['registrations'] as $reg) {
if ($reg->userId === $userId) { if ($reg->userId === $userId) {
$ids[] = $reg->credentialId; $ids[] = $reg->credentialId;
} }
} }
} }
} }
*/ */
if (count($ids) === 0) { if (count($ids) === 0) {
throw new Exception('no registrations in session for userId ' . $userId); throw new Exception('no registrations in session for userId ' . $userId);
} }
$getArgs = $WebAuthn->getGetArgs($ids, 60*4, true, true, true, true, true, $userVerification); $getArgs = $WebAuthn->getGetArgs($ids, 60*4, true, true, true, true, true, $userVerification);
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($getArgs)); print(json_encode($getArgs));
// save challange to session. you have to deliver it to processGet later. // save challange to session. you have to deliver it to processGet later.
$_SESSION['challenge'] = $WebAuthn->getChallenge(); $_SESSION['challenge'] = $WebAuthn->getChallenge();
// ------------------------------------ // ------------------------------------
// process create // process create
// ------------------------------------ // ------------------------------------
} else if ($fn === 'processCreate') { } else if ($fn === 'processCreate') {
$mysql = new mysqli($mysql_server,$mysql_user,$mysql_pass,$mysql_db); $mysql = new mysqli($mysql_server,$mysql_user,$mysql_pass,$mysql_db);
$clientDataJSON = !empty($post->clientDataJSON) ? base64_decode($post->clientDataJSON) : null; $clientDataJSON = !empty($post->clientDataJSON) ? base64_decode($post->clientDataJSON) : null;
$attestationObject = !empty($post->attestationObject) ? base64_decode($post->attestationObject) : null; $attestationObject = !empty($post->attestationObject) ? base64_decode($post->attestationObject) : null;
$challenge = $_SESSION['challenge'] ?? null; $challenge = $_SESSION['challenge'] ?? null;
// processCreate returns data to be stored for future logins. // processCreate returns data to be stored for future logins.
// in this example we store it in the php session. // in this example we store it in the php session.
// Normally you have to store the data in a database connected // Normally you have to store the data in a database connected
// with the username. // with the username.
$data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $challenge, $userVerification === 'required', true, false); $data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $challenge, $userVerification === 'required', true, false);
// add user infos // add user infos
$data->userId = $userId; $data->userId = $userId;
$data->userName = $userName; $data->userName = $userName;
$data->userDisplayName = $userDisplayName; $data->userDisplayName = $userDisplayName;
//set Null to 0 //set Null to 0
$data->signatureCounter ??= 0; $data->signatureCounter ??= 0;
/* /*
if (!isset($_SESSION['registrations']) || !array_key_exists('registrations', $_SESSION) || !is_array($_SESSION['registrations'])) { if (!isset($_SESSION['registrations']) || !array_key_exists('registrations', $_SESSION) || !is_array($_SESSION['registrations'])) {
$_SESSION['registrations'] = []; $_SESSION['registrations'] = [];
}*/ }*/
if(!mysqli_query($mysql,"INSERT INTO users SET userId = '".base64_encode($data->userId)."', credentialId = '".base64_encode($data->credentialId)."', credentialPublicKey = '".base64_encode($data->credentialPublicKey)."', signatureCounter = '".base64_encode($data->signatureCounter)."', name = '".mysqli_real_escape_string($mysql,filter_input(INPUT_GET, 'name'))."';")){ if(!mysqli_query($mysql,"INSERT INTO users SET userId = '".base64_encode($data->userId)."', credentialId = '".base64_encode($data->credentialId)."', credentialPublicKey = '".base64_encode($data->credentialPublicKey)."', signatureCounter = '".base64_encode($data->signatureCounter)."', name = '".mysqli_real_escape_string($mysql,filter_input(INPUT_GET, 'name'))."';")){
$msg = "Error:<br>".mysqli_error($mysql)."<br />"; $msg = "Error:<br>".mysqli_error($mysql)."<br />";
} }
else{ else{
if ($data->rootValid === false) { if ($data->rootValid === false) {
$msg = 'registration ok, but certificate does not match any of the selected root ca.'; $msg = 'registration ok, but certificate does not match any of the selected root ca.';
} }
// $msg = "Data: ".json_last_error();//json_encode($data);//'registration success.'; // $msg = "Data: ".json_last_error();//json_encode($data);//'registration success.';
} }
/* /*
$_SESSION['registrations'][] = $data; $_SESSION['registrations'][] = $data;
*/ */
$return = new stdClass(); $return = new stdClass();
$return->success = true; $return->success = true;
$return->msg = $msg; $return->msg = $msg;
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($return)); print(json_encode($return));
// ------------------------------------ // ------------------------------------
// proccess get // proccess get
// ------------------------------------ // ------------------------------------
} else if ($fn === 'processGet') { } else if ($fn === 'processGet') {
$clientDataJSON = !empty($post->clientDataJSON) ? base64_decode($post->clientDataJSON) : null; $clientDataJSON = !empty($post->clientDataJSON) ? base64_decode($post->clientDataJSON) : null;
$authenticatorData = !empty($post->authenticatorData) ? base64_decode($post->authenticatorData) : null; $authenticatorData = !empty($post->authenticatorData) ? base64_decode($post->authenticatorData) : null;
$signature = !empty($post->signature) ? base64_decode($post->signature) : null; $signature = !empty($post->signature) ? base64_decode($post->signature) : null;
$userHandle = !empty($post->userHandle) ? base64_decode($post->userHandle) : null; $userHandle = !empty($post->userHandle) ? base64_decode($post->userHandle) : null;
$id = !empty($post->id) ? base64_decode($post->id) : null; $id = !empty($post->id) ? base64_decode($post->id) : null;
$challenge = $_SESSION['challenge'] ?? ''; $challenge = $_SESSION['challenge'] ?? '';
$credentialPublicKey = null; $credentialPublicKey = null;
// looking up correspondending public key of the credential id // looking up correspondending public key of the credential id
// you should also validate that only ids of the given user name // you should also validate that only ids of the given user name
// are taken for the login. // are taken for the login.
$mysql_server = "localhost:3310"; $mysql_server = "localhost:3310";
$mysql_user = "Logins"; $mysql_user = "Logins";
$mysql_pass = "SPykMjT(CC.P_*b7"; $mysql_pass = "SPykMjT(CC.P_*b7";
$mysql_db = "Logins"; $mysql_db = "Logins";
$mysql = new mysqli($mysql_server,$mysql_user,$mysql_pass,$mysql_db); $mysql = new mysqli($mysql_server,$mysql_user,$mysql_pass,$mysql_db);
$result = mysqli_query($mysql,"SELECT credentialPublicKey, userId, name FROM users WHERE credentialId = '".base64_encode($id)."';"); $result = mysqli_query($mysql,"SELECT credentialPublicKey, userId, name FROM users WHERE credentialId = '".base64_encode($id)."';");
if(!$result){ if(!$result){
$msg = "Error:<br>".mysqli_error($mysql)."<br />"; $msg = "Error:<br>".mysqli_error($mysql)."<br />";
} }
if ($result->num_rows > 0) { if ($result->num_rows > 0) {
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
$credentialPublicKey = base64_decode($row["credentialPublicKey"]); $credentialPublicKey = base64_decode($row["credentialPublicKey"]);
$reg = (object) ['userId' => base64_decode($row["userId"])]; $reg = (object) ['userId' => base64_decode($row["userId"])];
$username = $row["name"]; $username = $row["name"];
} /*else { } /*else {
if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) { if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) {
foreach ($_SESSION['registrations'] as $reg) { foreach ($_SESSION['registrations'] as $reg) {
if ($reg->credentialId === $id) { if ($reg->credentialId === $id) {
$credentialPublicKey = $reg->credentialPublicKey; $credentialPublicKey = $reg->credentialPublicKey;
break; break;
} }
} }
} }
}*/ }*/
if ($credentialPublicKey === null) { if ($credentialPublicKey === null) {
throw new Exception('Public Key for credential ID not found!'); throw new Exception('Public Key for credential ID not found!');
} }
// if we have resident key, we have to verify that the userHandle is the provided userId at registration // if we have resident key, we have to verify that the userHandle is the provided userId at registration
if ($requireResidentKey && $userHandle !== hex2bin($reg->userId)) { if ($requireResidentKey && $userHandle !== hex2bin($reg->userId)) {
throw new \Exception('userId doesnt match (is ' . bin2hex($userHandle) . ' but expect ' . $reg->userId . ')'); throw new \Exception('userId doesnt match (is ' . bin2hex($userHandle) . ' but expect ' . $reg->userId . ')');
} }
// process the get request. throws WebAuthnException if it fails // process the get request. throws WebAuthnException if it fails
$WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $credentialPublicKey, $challenge, null, $userVerification === 'required'); $WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $credentialPublicKey, $challenge, null, $userVerification === 'required');
$return = new stdClass(); $return = new stdClass();
$return->success = true; $return->success = true;
$authKey = strval(random_int(0,99999999)); $authKey = strval(random_int(0,99999999));
$result = mysqli_query($mysql,"UPDATE users SET authKey=".$authKey.", lastAuth=NOW() WHERE credentialId = '".base64_encode($id)."';"); $result = mysqli_query($mysql,"UPDATE users SET authKey=".$authKey.", lastAuth=NOW() WHERE credentialId = '".base64_encode($id)."';");
$_SESSION["Logged"] = true; $_SESSION["Logged"] = true;
$_SESSION["user"] = $username; $_SESSION["user"] = $username;
$_SESSION["authKey"] = $authKey; $_SESSION["authKey"] = $authKey;
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($return)); print(json_encode($return));
// ------------------------------------ // ------------------------------------
// proccess clear registrations // proccess clear registrations
// ------------------------------------ // ------------------------------------
} else if ($fn === 'clearRegistrations') { } else if ($fn === 'clearRegistrations') {
$_SESSION['registrations'] = null; $_SESSION['registrations'] = null;
$_SESSION['challenge'] = null; $_SESSION['challenge'] = null;
$return = new stdClass(); $return = new stdClass();
$return->success = true; $return->success = true;
$return->msg = 'all registrations deleted'; $return->msg = 'all registrations deleted';
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($return)); print(json_encode($return));
// ------------------------------------ // ------------------------------------
// display stored data as HTML // display stored data as HTML
// ------------------------------------ // ------------------------------------
} /*else if ($fn === 'getStoredDataHtml') { } /*else if ($fn === 'getStoredDataHtml') {
$html = '<!DOCTYPE html>' . "\n"; $html = '<!DOCTYPE html>' . "\n";
$html .= '<html><head><style>tr:nth-child(even){background-color: #f2f2f2;}</style></head>'; $html .= '<html><head><style>tr:nth-child(even){background-color: #f2f2f2;}</style></head>';
$html .= '<body style="font-family:sans-serif">'; $html .= '<body style="font-family:sans-serif">';
if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) { if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) {
$html .= '<p>There are ' . count($_SESSION['registrations']) . ' registrations in this session:</p>'; $html .= '<p>There are ' . count($_SESSION['registrations']) . ' registrations in this session:</p>';
foreach ($_SESSION['registrations'] as $reg) { foreach ($_SESSION['registrations'] as $reg) {
$html .= '<table style="border:1px solid black;margin:10px 0;">'; $html .= '<table style="border:1px solid black;margin:10px 0;">';
foreach ($reg as $key => $value) { foreach ($reg as $key => $value) {
if (is_bool($value)) { if (is_bool($value)) {
$value = $value ? 'yes' : 'no'; $value = $value ? 'yes' : 'no';
} else if (is_null($value)) { } else if (is_null($value)) {
$value = 'null'; $value = 'null';
} else if (is_object($value)) { } else if (is_object($value)) {
$value = chunk_split(strval($value), 64); $value = chunk_split(strval($value), 64);
} else if (is_string($value) && strlen($value) > 0 && htmlspecialchars($value, ENT_QUOTES) === '') { } else if (is_string($value) && strlen($value) > 0 && htmlspecialchars($value, ENT_QUOTES) === '') {
$value = chunk_split(bin2hex($value), 64); $value = chunk_split(bin2hex($value), 64);
} }
$html .= '<tr><td>' . htmlspecialchars($key) . '</td><td style="font-family:monospace;">' . nl2br(htmlspecialchars($value)) . '</td>'; $html .= '<tr><td>' . htmlspecialchars($key) . '</td><td style="font-family:monospace;">' . nl2br(htmlspecialchars($value)) . '</td>';
} }
$html .= '</table>'; $html .= '</table>';
} }
} else { } else {
$html .= '<p>There are no registrations.</p>'; $html .= '<p>There are no registrations.</p>';
} }
$html .= '</body></html>'; $html .= '</body></html>';
header('Content-Type: text/html'); header('Content-Type: text/html');
print $html; print $html;
// ------------------------------------ // ------------------------------------
// get root certs from FIDO Alliance Metadata Service // get root certs from FIDO Alliance Metadata Service
// ------------------------------------ // ------------------------------------
} */else if ($fn === 'queryFidoMetaDataService') { } */else if ($fn === 'queryFidoMetaDataService') {
$mdsFolder = './restricted/WebAuthn/rootCertificates/mds'; $mdsFolder = './restricted/WebAuthn/rootCertificates/mds';
$success = false; $success = false;
$msg = null; $msg = null;
// fetch only 1x / 24h // fetch only 1x / 24h
$lastFetch = \is_file($mdsFolder . '/lastMdsFetch.txt') ? \strtotime(\file_get_contents($mdsFolder . '/lastMdsFetch.txt')) : 0; $lastFetch = \is_file($mdsFolder . '/lastMdsFetch.txt') ? \strtotime(\file_get_contents($mdsFolder . '/lastMdsFetch.txt')) : 0;
if ($lastFetch + (3600*48) < \time()) { if ($lastFetch + (3600*48) < \time()) {
$cnt = $WebAuthn->queryFidoMetaDataService($mdsFolder); $cnt = $WebAuthn->queryFidoMetaDataService($mdsFolder);
$success = true; $success = true;
\file_put_contents($mdsFolder . '/lastMdsFetch.txt', date('r')); \file_put_contents($mdsFolder . '/lastMdsFetch.txt', date('r'));
$msg = 'successfully queried FIDO Alliance Metadata Service - ' . $cnt . ' certificates downloaded.'; $msg = 'successfully queried FIDO Alliance Metadata Service - ' . $cnt . ' certificates downloaded.';
} else { } else {
$msg = 'Fail: last fetch was at ' . date('r', $lastFetch) . ' - fetch only 1x every 48h'; $msg = 'Fail: last fetch was at ' . date('r', $lastFetch) . ' - fetch only 1x every 48h';
} }
$return = new stdClass(); $return = new stdClass();
$return->success = $success; $return->success = $success;
$return->msg = $msg; $return->msg = $msg;
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($return)); print(json_encode($return));
} }
} catch (Throwable $ex) { } catch (Throwable $ex) {
$return = new stdClass(); $return = new stdClass();
$return->success = false; $return->success = false;
$return->msg = $ex->getMessage(); $return->msg = $ex->getMessage();
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($return)); print(json_encode($return));
} }

File diff suppressed because it is too large Load Diff

12
css/adminlte.min.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
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}} 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}}

File diff suppressed because one or more lines are too long

View File

@ -1,13 +1,13 @@
.winddir { .winddir {
position:absolute; position:absolute;
left:60%; left:60%;
width:25%; width:25%;
height:40%; height:40%;
padding: 0; padding: 0;
background-image: url('../assets/img/arrow.svg'); background-image: url('../assets/img/arrow.svg');
background-size:contain; background-size:contain;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
} }

View File

@ -1,52 +1,52 @@
<?php <?php
session_start(); session_start();
require_once("restricted/mysql.php"); require_once("restricted/mysql.php");
$_SESSION["local"] =false; $_SESSION["local"] =false;
function isLocal(){ function isLocal(){
$ipv6_prefix = explode(":",$_SERVER['SERVER_ADDR'],5); $ipv6_prefix = explode(":",$_SERVER['SERVER_ADDR'],5);
$ipv6 = explode(":",$_SERVER['REMOTE_ADDR'],5); $ipv6 = explode(":",$_SERVER['REMOTE_ADDR'],5);
if(($ipv6_prefix[0] == $ipv6[0] && $ipv6_prefix[1] == $ipv6[1] && $ipv6_prefix[2] == $ipv6[2] && $ipv6_prefix[3] == $ipv6[3]) || str_starts_with($_SERVER['REMOTE_ADDR'],"192.168.179.")){ if(($ipv6_prefix[0] == $ipv6[0] && $ipv6_prefix[1] == $ipv6[1] && $ipv6_prefix[2] == $ipv6[2] && $ipv6_prefix[3] == $ipv6[3]) || str_starts_with($_SERVER['REMOTE_ADDR'],"192.168.179.")){
$_SESSION["local"] =true; $_SESSION["local"] =true;
return true; return true;
}else{ }else{
return false; return false;
} }
} }
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()){
$_SESSION["local"] =true; $_SESSION["local"] =true;
return true; return true;
} }
if(isset($_SESSION["authKey"])){ if(isset($_SESSION["authKey"])){
$res = mysqli_query($mysql,"SELECT id FROM users WHERE lastAuth > DATE_SUB(NOW(), INTERVAL 2 DAY) AND authKey = '".mysqli_real_escape_string($mysql,$_SESSION["authKey"])."' AND name = '".mysqli_real_escape_string($mysql,$_SESSION["user"])."';"); $res = mysqli_query($mysql,"SELECT id FROM users WHERE lastAuth > DATE_SUB(NOW(), INTERVAL 2 DAY) AND authKey = '".mysqli_real_escape_string($mysql,$_SESSION["authKey"])."' AND name = '".mysqli_real_escape_string($mysql,$_SESSION["user"])."';");
if(!$res){ if(!$res){
echo mysqli_error($mysql); echo mysqli_error($mysql);
return false; return false;
} }
if(mysqli_num_rows($res) == 1){ if(mysqli_num_rows($res) == 1){
return isset($_SESSION["Logged"]); return isset($_SESSION["Logged"]);
} }
}else{ }else{
return false; return false;
} }
} }
function checkAdduser(){ function checkAdduser(){
$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(!mysqli_query($mysql,"DELETE FROM addUser WHERE datetime < DATE_SUB(NOW(), INTERVAL 1 MINUTE);")){ if(!mysqli_query($mysql,"DELETE FROM addUser WHERE datetime < DATE_SUB(NOW(), INTERVAL 1 MINUTE);")){
echo mysqli_error($mysql); echo mysqli_error($mysql);
} }
$result = mysqli_query($mysql,"SELECT * FROM addUser WHERE accesskey='".mysqli_real_escape_string($mysql,$_GET["addUser"])."';"); $result = mysqli_query($mysql,"SELECT * FROM addUser WHERE accesskey='".mysqli_real_escape_string($mysql,$_GET["addUser"])."';");
if(!$result){ if(!$result){
return false; return false;
} }
if ($result->num_rows > 0) { if ($result->num_rows > 0) {
return true; return true;
} }
return false; return false;
} }
?> ?>

286
index.php
View File

@ -1,143 +1,143 @@
<?php <?php
require_once("helper.php"); require_once("helper.php");
if (isset($_GET["addUser"])) { if (isset($_GET["addUser"])) {
if (checkAdduser($_GET["addUser"])) { if (checkAdduser($_GET["addUser"])) {
echo <<<ENDE echo <<<ENDE
<html> <html>
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Smarthome control</title> <title>Smarthome control</title>
<link rel="icon" type="image/png" href="assets/img/favicon.png"> <link rel="icon" type="image/png" href="assets/img/favicon.png">
<!--end::Accessibility Meta Tags--> <!--end::Accessibility Meta Tags-->
<!--begin::Primary Meta Tags--> <!--begin::Primary Meta Tags-->
<meta name="title" content="Smarthome control" /> <meta name="title" content="Smarthome control" />
<meta name="author" content="ColorlibHQ" /> <meta name="author" content="ColorlibHQ" />
<meta name="description" content="Smarthome control panel by m0." /> <meta name="description" content="Smarthome control panel by m0." />
<meta name="keywords" content="smarthome dashboard, admin panel" /> <meta name="keywords" content="smarthome dashboard, admin panel" />
<!--end::Primary Meta Tags--> <!--end::Primary Meta Tags-->
<!--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) <!--begin::Third Party Plugin(OverlayScrollbars)
<link rel="stylesheet" href="css/overlayscrollbars.min.css" />--> <link rel="stylesheet" href="css/overlayscrollbars.min.css" />-->
<!--end::Third Party Plugin(OverlayScrollbars)--> <!--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.css?v=2" />
<!--end::Required Plugin(AdminLTE)--> <!--end::Required Plugin(AdminLTE)-->
</head> </head>
<body onload="createRegistration()"> <body onload="createRegistration()">
</body> </body>
<script src="js/auth.js"></script> <script src="js/auth.js"></script>
<script> <script>
async function createRegistration() { async function createRegistration() {
try { try {
// check browser support // check browser support
if (!window.fetch || !navigator.credentials || !navigator.credentials.create) { if (!window.fetch || !navigator.credentials || !navigator.credentials.create) {
throw new Error('Browser not supported.'); throw new Error('Browser not supported.');
} }
let keyName = encodeURIComponent(prompt('Bitte Hier den Namen des Schlüssels eingeben:')); let keyName = encodeURIComponent(prompt('Bitte Hier den Namen des Schlüssels eingeben:'));
// get create args // get create args
let rep = await window.fetch('authServer.php?fn=getCreateArgs', {method:'GET', cache:'no-cache'}); let rep = await window.fetch('authServer.php?fn=getCreateArgs', {method:'GET', cache:'no-cache'});
//alert(await rep.text()); //alert(await rep.text());
const createArgs = await rep.json(); const createArgs = await rep.json();
// error handling // error handling
if (createArgs.success === false) { if (createArgs.success === false) {
throw new Error(createArgs.msg || 'unknown error occured'); throw new Error(createArgs.msg || 'unknown error occured');
} }
// replace binary base64 data with ArrayBuffer. a other way to do this // replace binary base64 data with ArrayBuffer. a other way to do this
// is the reviver function of JSON.parse() // is the reviver function of JSON.parse()
recursiveBase64StrToArrayBuffer(createArgs); recursiveBase64StrToArrayBuffer(createArgs);
// create credentials // create credentials
const cred = await navigator.credentials.create(createArgs); const cred = await navigator.credentials.create(createArgs);
// create object // create object
const authenticatorAttestationResponse = { const authenticatorAttestationResponse = {
transports: cred.response.getTransports ? cred.response.getTransports() : null, transports: cred.response.getTransports ? cred.response.getTransports() : null,
clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null, clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
attestationObject: cred.response.attestationObject ? arrayBufferToBase64(cred.response.attestationObject) : null attestationObject: cred.response.attestationObject ? arrayBufferToBase64(cred.response.attestationObject) : null
}; };
// check auth on server side // check auth on server side
rep = await window.fetch('authServer.php?fn=processCreate&name='+keyName, { rep = await window.fetch('authServer.php?fn=processCreate&name='+keyName, {
method : 'POST', method : 'POST',
body : JSON.stringify(authenticatorAttestationResponse), body : JSON.stringify(authenticatorAttestationResponse),
cache : 'no-cache' cache : 'no-cache'
}); });
authenticatorAttestationServerResponse = await rep.json(); authenticatorAttestationServerResponse = await rep.json();
// prompt server response // prompt server response
if (authenticatorAttestationServerResponse.success) { if (authenticatorAttestationServerResponse.success) {
window.alert(authenticatorAttestationServerResponse.msg || 'registration success'); window.alert(authenticatorAttestationServerResponse.msg || 'registration success');
if(!authenticatorAttestationServerResponse.msg){ if(!authenticatorAttestationServerResponse.msg){
window.location.href = "https://nas.el-wa.org/smart"; window.location.href = "https://nas.el-wa.org/smart";
} }
} else { } else {
throw new Error(authenticatorAttestationServerResponse.msg); throw new Error(authenticatorAttestationServerResponse.msg);
} }
} catch (err) { } catch (err) {
window.alert(err.message || 'unknown error occured'); window.alert(err.message || 'unknown error occured');
} }
} }
</script> </script>
</html> </html>
ENDE; ENDE;
} }
} else if (checkLogin()) { } else if (checkLogin()) {
include "restricted/header.php"; include "restricted/header.php";
if(!isset($_GET["action"])){ if(!isset($_GET["action"])){
$_GET["action"] = "solar"; $_GET["action"] = "solar";
} }
$resource_content = ""; $resource_content = "";
switch($_GET["action"]){ switch($_GET["action"]){
case "solar": case "solar":
$resource_content .= str_replace("%%INSERTSVG%%", file_get_contents('assets/img/realtime.svg'), file_get_contents('restricted/solar.html')); $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 .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/solarMQTT.js'></script>"; $resource_content .= "<script src='js/solar/solarMQTT.js'></script>";
break; break;
case "home": case "home":
include "restricted/home.php"; include "restricted/home.php";
$resource_content .= file_get_contents('restricted/footer.html'); $resource_content .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/autoActionFuncs.js'></script>"; $resource_content .= "<script src='js/solar/autoActionFuncs.js'></script>";
$resource_content .= "<script src='js/solar/homeMQTT.js'></script>"; $resource_content .= "<script src='js/solar/homeMQTT.js'></script>";
break; break;
case "heat": case "heat":
$resource_content .= file_get_contents('restricted/heat.html'); $resource_content .= file_get_contents('restricted/heat.html');
$resource_content .= file_get_contents('restricted/footer.html'); $resource_content .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/heatMQTT.js'></script>"; $resource_content .= "<script src='js/solar/heatMQTT.js'></script>";
break; break;
case "history": case "history":
$resource_content .= file_get_contents('restricted/history.html'); $resource_content .= file_get_contents('restricted/history.html');
$resource_content .= file_get_contents('restricted/footer.html'); $resource_content .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/historyMQTT.js'></script>"; $resource_content .= "<script src='js/solar/historyMQTT.js'></script>";
break; break;
} }
echo $resource_content; echo $resource_content;
} else { } else {
echo <<<ENDE echo <<<ENDE
<html> <html>
<head><link rel="icon" type="image/png" href="assets/img/favicon.png"></head> <head><link rel="icon" type="image/png" href="assets/img/favicon.png"></head>
<body onload="checkRegistration()"> <body onload="checkRegistration()">
<script src="js/auth.js"></script> <script src="js/auth.js"></script>
</body> </body>
</html> </html>
ENDE; ENDE;
} }

2
js/Sortable.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

12
js/adminlte.min.js vendored

File diff suppressed because one or more lines are too long

28
js/apexcharts.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,149 +1,149 @@
async function checkRegistration() { async function checkRegistration() {
try { try {
if (!window.fetch || !navigator.credentials || !navigator.credentials.create) { if (!window.fetch || !navigator.credentials || !navigator.credentials.create) {
throw new Error('Browser not supported.'); throw new Error('Browser not supported.');
} }
// get check args // get check args
let rep = await window.fetch('authServer.php?fn=getGetArgs' + getGetParams(), {method:'GET',cache:'no-cache'}); let rep = await window.fetch('authServer.php?fn=getGetArgs' + getGetParams(), {method:'GET',cache:'no-cache'});
const getArgs = await rep.json(); const getArgs = await rep.json();
// error handling // error handling
if (getArgs.success === false) { if (getArgs.success === false) {
throw new Error(getArgs.msg); throw new Error(getArgs.msg);
} }
// replace binary base64 data with ArrayBuffer. a other way to do this // replace binary base64 data with ArrayBuffer. a other way to do this
// is the reviver function of JSON.parse() // is the reviver function of JSON.parse()
recursiveBase64StrToArrayBuffer(getArgs); recursiveBase64StrToArrayBuffer(getArgs);
// check credentials with hardware // check credentials with hardware
const cred = await navigator.credentials.get(getArgs); const cred = await navigator.credentials.get(getArgs);
// create object for transmission to server // create object for transmission to server
const authenticatorAttestationResponse = { const authenticatorAttestationResponse = {
id: cred.rawId ? arrayBufferToBase64(cred.rawId) : null, id: cred.rawId ? arrayBufferToBase64(cred.rawId) : null,
clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null, clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
authenticatorData: cred.response.authenticatorData ? arrayBufferToBase64(cred.response.authenticatorData) : null, authenticatorData: cred.response.authenticatorData ? arrayBufferToBase64(cred.response.authenticatorData) : null,
signature: cred.response.signature ? arrayBufferToBase64(cred.response.signature) : null, signature: cred.response.signature ? arrayBufferToBase64(cred.response.signature) : null,
userHandle: cred.response.userHandle ? arrayBufferToBase64(cred.response.userHandle) : null userHandle: cred.response.userHandle ? arrayBufferToBase64(cred.response.userHandle) : null
}; };
// send to server // send to server
rep = await window.fetch('authServer.php?fn=processGet' + getGetParams(), { rep = await window.fetch('authServer.php?fn=processGet' + getGetParams(), {
method:'POST', method:'POST',
body: JSON.stringify(authenticatorAttestationResponse), body: JSON.stringify(authenticatorAttestationResponse),
cache:'no-cache' cache:'no-cache'
}); });
const authenticatorAttestationServerResponse = await rep.json(); const authenticatorAttestationServerResponse = await rep.json();
// check server response // check server response
if (authenticatorAttestationServerResponse.success) { if (authenticatorAttestationServerResponse.success) {
window.location.reload(); window.location.reload();
/// window.alert(authenticatorAttestationServerResponse.msg || 'login success'); /// window.alert(authenticatorAttestationServerResponse.msg || 'login success');
} else { } else {
throw new Error(authenticatorAttestationServerResponse.msg); throw new Error(authenticatorAttestationServerResponse.msg);
} }
} catch (err) { } catch (err) {
//reloadServerPreview(); //reloadServerPreview();
window.alert(err.message || 'unknown error occured'); window.alert(err.message || 'unknown error occured');
} }
} }
function queryFidoMetaDataService() { function queryFidoMetaDataService() {
window.fetch('authServer.php?fn=queryFidoMetaDataService' + getGetParams(), {method:'GET',cache:'no-cache'}).then(function(response) { window.fetch('authServer.php?fn=queryFidoMetaDataService' + getGetParams(), {method:'GET',cache:'no-cache'}).then(function(response) {
return response.json(); return response.json();
}).then(function(json) { }).then(function(json) {
if (json.success) { if (json.success) {
window.alert(json.msg); window.alert(json.msg);
} else { } else {
throw new Error(json.msg); throw new Error(json.msg);
} }
}).catch(function(err) { }).catch(function(err) {
window.alert(err.message || 'unknown error occured'); window.alert(err.message || 'unknown error occured');
}); });
} }
/** /**
* convert RFC 1342-like base64 strings to array buffer * convert RFC 1342-like base64 strings to array buffer
* @param {mixed} obj * @param {mixed} obj
* @returns {undefined} * @returns {undefined}
*/ */
function recursiveBase64StrToArrayBuffer(obj) { function recursiveBase64StrToArrayBuffer(obj) {
let prefix = '=?BINARY?B?'; let prefix = '=?BINARY?B?';
let suffix = '?='; let suffix = '?=';
if (typeof obj === 'object') { if (typeof obj === 'object') {
for (let key in obj) { for (let key in obj) {
if (typeof obj[key] === 'string') { if (typeof obj[key] === 'string') {
let str = obj[key]; let str = obj[key];
if (str.substring(0, prefix.length) === prefix && str.substring(str.length - suffix.length) === suffix) { if (str.substring(0, prefix.length) === prefix && str.substring(str.length - suffix.length) === suffix) {
str = str.substring(prefix.length, str.length - suffix.length); str = str.substring(prefix.length, str.length - suffix.length);
let binary_string = window.atob(str); let binary_string = window.atob(str);
let len = binary_string.length; let len = binary_string.length;
let bytes = new Uint8Array(len); let bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i); bytes[i] = binary_string.charCodeAt(i);
} }
obj[key] = bytes.buffer; obj[key] = bytes.buffer;
} }
} else { } else {
recursiveBase64StrToArrayBuffer(obj[key]); recursiveBase64StrToArrayBuffer(obj[key]);
} }
} }
} }
} }
/** /**
* Convert a ArrayBuffer to Base64 * Convert a ArrayBuffer to Base64
* @param {ArrayBuffer} buffer * @param {ArrayBuffer} buffer
* @returns {String} * @returns {String}
*/ */
function arrayBufferToBase64(buffer) { function arrayBufferToBase64(buffer) {
let binary = ''; let binary = '';
let bytes = new Uint8Array(buffer); let bytes = new Uint8Array(buffer);
let len = bytes.byteLength; let len = bytes.byteLength;
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] ); binary += String.fromCharCode( bytes[ i ] );
} }
return window.btoa(binary); return window.btoa(binary);
} }
/** /**
* Get URL parameter * Get URL parameter
* @returns {String} * @returns {String}
*/ */
function getGetParams() { function getGetParams() {
let url = ''; let url = '';
url += '&apple=1'; url += '&apple=1';
url += '&yubico=1'; url += '&yubico=1';
url += '&solo=1'; url += '&solo=1';
url += '&hypersecu=1'; url += '&hypersecu=1';
url += '&google=1'; url += '&google=1';
url += '&microsoft=1'; url += '&microsoft=1';
url += '&mds=1'; url += '&mds=1';
url += '&requireResidentKey=0'; url += '&requireResidentKey=0';
url += '&type_usb=1'; url += '&type_usb=1';
url += '&type_nfc=1'; url += '&type_nfc=1';
url += '&type_ble=1'; url += '&type_ble=1';
url += '&type_int=1'; url += '&type_int=1';
url += '&type_hybrid=1'; url += '&type_hybrid=1';
url += '&fmt_android-key=1'; url += '&fmt_android-key=1';
url += '&fmt_android-safetynet=1'; url += '&fmt_android-safetynet=1';
url += '&fmt_apple=1'; url += '&fmt_apple=1';
url += '&fmt_fido-u2f=1'; url += '&fmt_fido-u2f=1';
url += '&fmt_none=0' ; url += '&fmt_none=0' ;
url += '&fmt_packed=1'; url += '&fmt_packed=1';
url += '&fmt_tpm=1'; url += '&fmt_tpm=1';
url += '&userVerification=discouraged'; url += '&userVerification=discouraged';
return url; return url;
} }

12
js/bootstrap.min.js vendored

File diff suppressed because one or more lines are too long

26
js/chart.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
/*! /*!
* chartjs-adapter-luxon v1.3.1 * chartjs-adapter-luxon v1.3.1
* https://www.chartjs.org * https://www.chartjs.org
* (c) 2023 chartjs-adapter-luxon Contributors * (c) 2023 chartjs-adapter-luxon Contributors
* Released under the MIT license * 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()}})})); !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()}})}));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
/*! https://github.com/FranBar1966/bootstrap-5-modal-dynamic - License in the terms described in the LICENSE file */ /*! https://github.com/FranBar1966/bootstrap-5-modal-dynamic - License in the terms described in the LICENSE file */
function startDynamicModal(){document.body.removeEventListener("click",dynamicModalHandler),document.body.addEventListener("click",dynamicModalHandler)}function dynamicModalHandler(e){const t=e.target.closest(".modal-dynamic");if(!t)return;e.target.closest("a")&&e.preventDefault();const a=e.target.getAttribute("href"),d=e.target.dataset.template||"#modalTemplate";let o=document.querySelector(a);if(!o){const e=document.querySelector(d);e&&(o=e.cloneNode(!0),o.id=a.substring(1),document.body.appendChild(o))}if(!o)return;const n=e.target.dataset.class,r=e.target.dataset.title,s=e.target.dataset.header,l=e.target.dataset.noheader,c=e.target.dataset.url,i=e.target.dataset.footer,u=e.target.dataset.nofooter,m=e.target.dataset.width||"",y=e.target.dataset.backdrop||"false",h=!e.target.dataset.keyboard||"true"===e.target.dataset.keyboard;if(n&&o.classList.add(...n.split(" ")),s){const e=o.querySelector(".modal-header"),t=document.querySelector(s);e&&t&&(e.innerHTML=t.innerHTML)}if(l){const e=o.querySelector(".modal-header");e&&e.classList.add("hidden","d-none")}if(r){const e=o.querySelector(".modal-title");e&&(e.innerHTML=r)}if(i){const e=o.querySelector(".modal-footer"),t=document.querySelector(i);e&&t&&(e.innerHTML=t.innerHTML)}if(u){const e=o.querySelector(".modal-footer");e&&e.classList.add("hidden","d-none")}if(m){const e=o.querySelector(".modal-dialog");if(e){const t=isNaN(m)||""===m?m:m+"px";e.style.maxWidth=t,e.style.width="auto"}}let f=bootstrap.Modal.getInstance(o);f||(f=new bootstrap.Modal(o,{keyboard:h,backdrop:y})),o.addEventListener("hidden.bs.modal",e=>{o.remove()}),o.addEventListener("shown.bs.modal",e=>{o.focus()}),f.show();const g=o.querySelector(".modal-body");if(c.startsWith("#")){const e=document.querySelector(c);g.innerHTML=e?e.innerHTML:"ERROR: Content not found"}else fetch(c,{method:"GET",headers:{"X-Requested-From-Modal":a.substring(1),"Requested-With-Ajax":"ajax"}}).then(e=>e.text()).then(e=>{g.innerHTML=e,window.dispatchEvent(new CustomEvent("neutralFetchCompleted",{detail:{element:o,url:c}}))}).catch(e=>{g.innerHTML=e.message,window.dispatchEvent(new CustomEvent("neutralFetchError",{detail:{element:o,url:c}}))})}startDynamicModal(),window.addEventListener("neutralFetchCompleted",()=>{startDynamicModal()}); function startDynamicModal(){document.body.removeEventListener("click",dynamicModalHandler),document.body.addEventListener("click",dynamicModalHandler)}function dynamicModalHandler(e){const t=e.target.closest(".modal-dynamic");if(!t)return;e.target.closest("a")&&e.preventDefault();const a=e.target.getAttribute("href"),d=e.target.dataset.template||"#modalTemplate";let o=document.querySelector(a);if(!o){const e=document.querySelector(d);e&&(o=e.cloneNode(!0),o.id=a.substring(1),document.body.appendChild(o))}if(!o)return;const n=e.target.dataset.class,r=e.target.dataset.title,s=e.target.dataset.header,l=e.target.dataset.noheader,c=e.target.dataset.url,i=e.target.dataset.footer,u=e.target.dataset.nofooter,m=e.target.dataset.width||"",y=e.target.dataset.backdrop||"false",h=!e.target.dataset.keyboard||"true"===e.target.dataset.keyboard;if(n&&o.classList.add(...n.split(" ")),s){const e=o.querySelector(".modal-header"),t=document.querySelector(s);e&&t&&(e.innerHTML=t.innerHTML)}if(l){const e=o.querySelector(".modal-header");e&&e.classList.add("hidden","d-none")}if(r){const e=o.querySelector(".modal-title");e&&(e.innerHTML=r)}if(i){const e=o.querySelector(".modal-footer"),t=document.querySelector(i);e&&t&&(e.innerHTML=t.innerHTML)}if(u){const e=o.querySelector(".modal-footer");e&&e.classList.add("hidden","d-none")}if(m){const e=o.querySelector(".modal-dialog");if(e){const t=isNaN(m)||""===m?m:m+"px";e.style.maxWidth=t,e.style.width="auto"}}let f=bootstrap.Modal.getInstance(o);f||(f=new bootstrap.Modal(o,{keyboard:h,backdrop:y})),o.addEventListener("hidden.bs.modal",e=>{o.remove()}),o.addEventListener("shown.bs.modal",e=>{o.focus()}),f.show();const g=o.querySelector(".modal-body");if(c.startsWith("#")){const e=document.querySelector(c);g.innerHTML=e?e.innerHTML:"ERROR: Content not found"}else fetch(c,{method:"GET",headers:{"X-Requested-From-Modal":a.substring(1),"Requested-With-Ajax":"ajax"}}).then(e=>e.text()).then(e=>{g.innerHTML=e,window.dispatchEvent(new CustomEvent("neutralFetchCompleted",{detail:{element:o,url:c}}))}).catch(e=>{g.innerHTML=e.message,window.dispatchEvent(new CustomEvent("neutralFetchError",{detail:{element:o,url:c}}))})}startDynamicModal(),window.addEventListener("neutralFetchCompleted",()=>{startDynamicModal()});

47790
js/mqtt.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

12
js/popper.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,295 +1,295 @@
function changeValueType(event){ function changeValueType(event){
dropdown = event.currentTarget; dropdown = event.currentTarget;
type = dropdown.options[dropdown.selectedIndex].dataset.type; type = dropdown.options[dropdown.selectedIndex].dataset.type;
id = dropdown.id.match(/\d+$/); id = dropdown.id.match(/\d+$/);
if(dropdown.id.search("act") > -1){ if(dropdown.id.search("act") > -1){
opBtnID = "btnActOperator"+id; opBtnID = "btnActOperator"+id;
valBlockID = "actValBlock"+id; valBlockID = "actValBlock"+id;
valElemID = "actValue"+id; valElemID = "actValue"+id;
}else{ }else{
opBtnID = "btnOperator"+id; opBtnID = "btnOperator"+id;
valBlockID ="valBlock"+id; valBlockID ="valBlock"+id;
valElemID = "threshold"+id; valElemID = "threshold"+id;
} }
if(type =="hidden"){ if(type =="hidden"){
document.getElementById(opBtnID).hidden = true; document.getElementById(opBtnID).hidden = true;
document.getElementById(valBlockID).hidden = true; document.getElementById(valBlockID).hidden = true;
}else{ }else{
document.getElementById(opBtnID).hidden = false; document.getElementById(opBtnID).hidden = false;
document.getElementById(valBlockID).hidden = false; document.getElementById(valBlockID).hidden = false;
document.getElementById(valElemID).type = type; document.getElementById(valElemID).type = type;
} }
} }
function fillSensorDD(ID){ function fillSensorDD(ID){
var elem = document.getElementById("sensorSelect"+ID); var elem = document.getElementById("sensorSelect"+ID);
fetch("./ajax/fillSensorDD.php", { fetch("./ajax/fillSensorDD.php", {
method: 'GET', method: 'GET',
headers: { headers: {
'X-Requested-From-Modal': 'a', 'X-Requested-From-Modal': 'a',
'Requested-With-Ajax': 'ajax' 'Requested-With-Ajax': 'ajax'
} }
}) })
.then(response => response.text()) .then(response => response.text())
.then(html => { .then(html => {
elem.innerHTML = html; elem.innerHTML = html;
elem.addEventListener("change", arrangeSensorInputs); elem.addEventListener("change", arrangeSensorInputs);
document.getElementById("paramSelect"+ID).addEventListener("change", changeValueType); document.getElementById("paramSelect"+ID).addEventListener("change", changeValueType);
elem.dispatchEvent(new Event('change')); elem.dispatchEvent(new Event('change'));
}) })
.catch(error => { .catch(error => {
elem.innerHTML = ""; elem.innerHTML = "";
}); });
} }
function fillActorDD(ID){ function fillActorDD(ID){
var elem = document.getElementById("actorSelect"+ID); var elem = document.getElementById("actorSelect"+ID);
fetch("./ajax/fillActorDD.php", { fetch("./ajax/fillActorDD.php", {
method: 'GET', method: 'GET',
headers: { headers: {
'X-Requested-From-Modal': 'a', 'X-Requested-From-Modal': 'a',
'Requested-With-Ajax': 'ajax' 'Requested-With-Ajax': 'ajax'
} }
}) })
.then(response => response.text()) .then(response => response.text())
.then(html => { .then(html => {
elem.innerHTML = html; elem.innerHTML = html;
elem.addEventListener("change", arrangeActorInputs); elem.addEventListener("change", arrangeActorInputs);
document.getElementById("actParamSelect"+ID).addEventListener("change", changeValueType); document.getElementById("actParamSelect"+ID).addEventListener("change", changeValueType);
document.getElementById("actorSelect"+ID).dispatchEvent(new Event('change')); document.getElementById("actorSelect"+ID).dispatchEvent(new Event('change'));
}) })
.catch(error => { .catch(error => {
elem.innerHTML = ""; elem.innerHTML = "";
}); });
} }
function changeAllIDs (parentNode, newID) { function changeAllIDs (parentNode, newID) {
for (var i = 0; i < parentNode.childNodes.length; i++) { for (var i = 0; i < parentNode.childNodes.length; i++) {
var child = parentNode.childNodes[i]; var child = parentNode.childNodes[i];
changeAllIDs(child, newID); changeAllIDs(child, newID);
} }
if(parentNode.id){ if(parentNode.id){
parentNode.id = parentNode.id.replace(/\d+$/, newID); parentNode.id = parentNode.id.replace(/\d+$/, newID);
} }
if(parentNode.dataset !== undefined){ if(parentNode.dataset !== undefined){
if(parentNode.dataset.delid) if(parentNode.dataset.delid)
parentNode.dataset.delid = parentNode.dataset.delid.replace(/\d+$/, newID); parentNode.dataset.delid = parentNode.dataset.delid.replace(/\d+$/, newID);
} }
} }
function delAutoEntry(event){ function delAutoEntry(event){
ID = event.currentTarget.dataset.delid; ID = event.currentTarget.dataset.delid;
document.getElementById(ID).remove(); document.getElementById(ID).remove();
ID = ID.replace(/\d+$/, function(n){ return ++n }); ID = ID.replace(/\d+$/, function(n){ return ++n });
while(sensor= document.getElementById(ID)){ while(sensor= document.getElementById(ID)){
changeAllIDs(sensor, ID.match(/\d+$/)-1); changeAllIDs(sensor, ID.match(/\d+$/)-1);
ID = ID.replace(/\d+$/, function(n){ return ++n }); ID = ID.replace(/\d+$/, function(n){ return ++n });
} }
} }
function addSensor(event){ function addSensor(event){
var t = document.getElementById('sensorsList').children; var t = document.getElementById('sensorsList').children;
//get the second last element (ignore "add" button) //get the second last element (ignore "add" button)
nextID = Number(t[t.length-1].id.replace("sensorSettings","")) + 1; nextID = Number(t[t.length-1].id.replace("sensorSettings","")) + 1;
var div = document.createElement('div'); var div = document.createElement('div');
div.className = "input-group mt-3"; div.className = "input-group mt-3";
div.id = "sensorSettings"+String(nextID); div.id = "sensorSettings"+String(nextID);
div.innerHTML = `<button class='btn btn-outline-secondary' type='button' id='btnLogic${nextID}' name='btnLogic${nextID}' data-tglstates='["und","oder"]' >und</button> div.innerHTML = `<button class='btn btn-outline-secondary' type='button' id='btnLogic${nextID}' name='btnLogic${nextID}' data-tglstates='["und","oder"]' >und</button>
<div class="form-floating"> <div class="form-floating">
<select class="form-select" id="sensorSelect${nextID}" name="sensorSelect${nextID}" aria-label="Default select example"> <select class="form-select" id="sensorSelect${nextID}" name="sensorSelect${nextID}" aria-label="Default select example">
</select> </select>
<label>Sensor</label> <label>Sensor</label>
</div> </div>
<div class="form-floating" id="paramBlock${nextID}"> <div class="form-floating" id="paramBlock${nextID}">
<select class="form-select" id="paramSelect${nextID}" name="paramSelect${nextID}" aria-label="Default select example"> <select class="form-select" id="paramSelect${nextID}" name="paramSelect${nextID}" aria-label="Default select example">
</select> </select>
<label>Messwert</label> <label>Messwert</label>
</div> </div>
<button class="btn btn-outline-secondary " type="button" id="btnOperator${nextID}" name="btnOperator${nextID}">&gt;</button> <button class="btn btn-outline-secondary " type="button" id="btnOperator${nextID}" name="btnOperator${nextID}">&gt;</button>
<div class="form-floating" id="valBlock${nextID}"> <div class="form-floating" id="valBlock${nextID}">
<input type="number" class="form-control" id="threshold${nextID}" name="threshold${nextID}" placeholder="0" value="0"></input> <input type="number" class="form-control" id="threshold${nextID}" name="threshold${nextID}" placeholder="0" value="0"></input>
<label>Wert/Schwelle</label> <label>Wert/Schwelle</label>
</div> </div>
<button class='btn btn-outline-danger' type='button' id='btnDel${nextID}' data-delid="sensorSettings${nextID}" onclick="delAutoEntry(event)"><i class="bi bi-trash3"></i></button> <button class='btn btn-outline-danger' type='button' id='btnDel${nextID}' data-delid="sensorSettings${nextID}" onclick="delAutoEntry(event)"><i class="bi bi-trash3"></i></button>
</div>`; </div>`;
document.getElementById("sensorsList").appendChild(div); document.getElementById("sensorsList").appendChild(div);
fillSensorDD(nextID); fillSensorDD(nextID);
} }
function addActor(event){ function addActor(event){
var t = document.getElementById('actorsList').children; var t = document.getElementById('actorsList').children;
//get the second last element (ignore "add" button) //get the second last element (ignore "add" button)
nextID = Number(t[t.length-1].id.replace("actorSettings","")) + 1; nextID = Number(t[t.length-1].id.replace("actorSettings","")) + 1;
var div = document.createElement('div'); var div = document.createElement('div');
div.className = "input-group mt-3"; div.className = "input-group mt-3";
div.id = "actorSettings"+String(nextID); div.id = "actorSettings"+String(nextID);
div.innerHTML = `<div class="form-floating"> div.innerHTML = `<div class="form-floating">
<select class="form-select" id="actorSelect${nextID}" name="actorSelect${nextID}" aria-label="Default select example"> <select class="form-select" id="actorSelect${nextID}" name="actorSelect${nextID}" aria-label="Default select example">
</select> </select>
<label>Aktor</label> <label>Aktor</label>
</div> </div>
<div class="form-floating" id="actParamBlock${nextID}"> <div class="form-floating" id="actParamBlock${nextID}">
<select class="form-select" id="actParamSelect${nextID}" name="actParamSelect${nextID}" aria-label="Default select example"> <select class="form-select" id="actParamSelect${nextID}" name="actParamSelect${nextID}" aria-label="Default select example">
</select> </select>
<label>Eigenschaft</label> <label>Eigenschaft</label>
</div> </div>
<button class="btn btn-outline-secondary " type="button" id="btnActOperator${nextID}" name="btnActOperator${nextID}">&gt;</button> <button class="btn btn-outline-secondary " type="button" id="btnActOperator${nextID}" name="btnActOperator${nextID}">&gt;</button>
<div class="form-floating" id="actValBlock${nextID}"> <div class="form-floating" id="actValBlock${nextID}">
<input type="number" class="form-control" id="actValue${nextID}" name="actValue${nextID}" placeholder="0" value="0"></input> <input type="number" class="form-control" id="actValue${nextID}" name="actValue${nextID}" placeholder="0" value="0"></input>
<label>Sollwert</label> <label>Sollwert</label>
</div> </div>
<button class='btn btn-outline-danger' type='button' id='btnActDel${nextID}' data-delid="actorSettings${nextID}" onclick="delAutoEntry(event)"><i class="bi bi-trash3"></i></button>`; <button class='btn btn-outline-danger' type='button' id='btnActDel${nextID}' data-delid="actorSettings${nextID}" onclick="delAutoEntry(event)"><i class="bi bi-trash3"></i></button>`;
document.getElementById("actorsList").appendChild(div); document.getElementById("actorsList").appendChild(div);
/*"afterend",`<div class='input-group mb-3' id='actorSettings${nextID}'> /*"afterend",`<div class='input-group mb-3' id='actorSettings${nextID}'>
<div class="form-floating"> <div class="form-floating">
<select class="form-select" id="actorSelect${nextID}" aria-label="Default select example"> <select class="form-select" id="actorSelect${nextID}" aria-label="Default select example">
</select> </select>
<label>Aktor</label> <label>Aktor</label>
</div> </div>
<div class="form-floating" id="actParamBlock${nextID}"> <div class="form-floating" id="actParamBlock${nextID}">
<select class="form-select" id="actParamSelect${nextID}" aria-label="Default select example"> <select class="form-select" id="actParamSelect${nextID}" aria-label="Default select example">
</select> </select>
<label>Eigenschaft</label> <label>Eigenschaft</label>
</div> </div>
<button class="btn btn-outline-secondary " type="button" id="btnActOperator${nextID}">&gt;</button> <button class="btn btn-outline-secondary " type="button" id="btnActOperator${nextID}">&gt;</button>
<div class="form-floating" id="actValBlock${nextID}"> <div class="form-floating" id="actValBlock${nextID}">
<input type="number" class="form-control" id="actValue${nextID}" placeholder="0" value="0"></input> <input type="number" class="form-control" id="actValue${nextID}" placeholder="0" value="0"></input>
<label>Sollwert</label> <label>Sollwert</label>
</div> </div>
<button class='btn btn-outline-danger' type='button' id='btnActDel${nextID}' data-delid="actorSettings${nextID}" onclick="delAutoEntry(event)"><i class="bi bi-trash3"></i></button> <button class='btn btn-outline-danger' type='button' id='btnActDel${nextID}' data-delid="actorSettings${nextID}" onclick="delAutoEntry(event)"><i class="bi bi-trash3"></i></button>
</div>`);*/ </div>`);*/
fillActorDD(nextID); fillActorDD(nextID);
} }
function arrangeSensorInputs(event){ function arrangeSensorInputs(event){
ID = Number(event.currentTarget.id.replace("sensorSelect","")); ID = Number(event.currentTarget.id.replace("sensorSelect",""));
sensorID = document.getElementById("sensorSelect"+ID).value; sensorID = document.getElementById("sensorSelect"+ID).value;
fetch("./ajax/sensorDetails.php?sensorID="+sensorID, { fetch("./ajax/sensorDetails.php?sensorID="+sensorID, {
method: 'GET', method: 'GET',
headers: { headers: {
'X-Requested-From-Modal': 'a', 'X-Requested-From-Modal': 'a',
'Requested-With-Ajax': 'ajax' 'Requested-With-Ajax': 'ajax'
} }
}) })
.then(response => response.text()) .then(response => response.text())
.then(html => { .then(html => {
params = JSON.parse(html); params = JSON.parse(html);
document.getElementById("paramSelect"+ID).innerHTML = ""; document.getElementById("paramSelect"+ID).innerHTML = "";
if(params.Parameters.length == 1){ if(params.Parameters.length == 1){
document.getElementById("paramBlock"+ID).hidden = true; document.getElementById("paramBlock"+ID).hidden = true;
}else{ }else{
document.getElementById("paramBlock"+ID).hidden = false; document.getElementById("paramBlock"+ID).hidden = false;
} }
params.Parameters.forEach((param, index) => { params.Parameters.forEach((param, index) => {
var option = document.createElement("option"); var option = document.createElement("option");
option.text = param.name; option.text = param.name;
option.value = index; option.value = index;
option.setAttribute("data-type",param.type); option.setAttribute("data-type",param.type);
document.getElementById("paramSelect"+ID).appendChild(option); document.getElementById("paramSelect"+ID).appendChild(option);
document.getElementById("btnOperator"+ID).setAttribute("data-tglstates",JSON.stringify(param.operators)); document.getElementById("btnOperator"+ID).setAttribute("data-tglstates",JSON.stringify(param.operators));
document.getElementById("btnOperator"+ID).innerHTML = param.operators[0]; document.getElementById("btnOperator"+ID).innerHTML = param.operators[0];
document.getElementById("btnOperator"+ID).addEventListener("click", tglOperators); document.getElementById("btnOperator"+ID).addEventListener("click", tglOperators);
if(document.getElementById("btnLogic"+ID)) if(document.getElementById("btnLogic"+ID))
document.getElementById("btnLogic"+ID).addEventListener("click", tglOperators); document.getElementById("btnLogic"+ID).addEventListener("click", tglOperators);
document.getElementById("threshold"+ID).setAttribute("type",param.type); document.getElementById("threshold"+ID).setAttribute("type",param.type);
}); });
document.getElementById("paramSelect"+ID).dispatchEvent(new Event('change')); document.getElementById("paramSelect"+ID).dispatchEvent(new Event('change'));
}) })
.catch(error => { .catch(error => {
alert(error); alert(error);
document.getElementById("paramSelect"+ID).innerHTML = ""; document.getElementById("paramSelect"+ID).innerHTML = "";
}); });
} }
function arrangeActorInputs(event){ function arrangeActorInputs(event){
ID = Number(event.currentTarget.id.replace("actorSelect","")); ID = Number(event.currentTarget.id.replace("actorSelect",""));
sensorID = document.getElementById("actorSelect"+ID).value; sensorID = document.getElementById("actorSelect"+ID).value;
fetch("./ajax/actorDetails.php?actorID="+sensorID, { fetch("./ajax/actorDetails.php?actorID="+sensorID, {
method: 'GET', method: 'GET',
headers: { headers: {
'X-Requested-From-Modal': 'a', 'X-Requested-From-Modal': 'a',
'Requested-With-Ajax': 'ajax' 'Requested-With-Ajax': 'ajax'
} }
}) })
.then(response => response.text()) .then(response => response.text())
.then(html => { .then(html => {
params = JSON.parse(html); params = JSON.parse(html);
document.getElementById("actParamSelect"+ID).innerHTML = ""; document.getElementById("actParamSelect"+ID).innerHTML = "";
if(params.Parameters.length == 1){ if(params.Parameters.length == 1){
document.getElementById("actParamBlock"+ID).hidden = true; document.getElementById("actParamBlock"+ID).hidden = true;
}else{ }else{
document.getElementById("actParamBlock"+ID).hidden = false; document.getElementById("actParamBlock"+ID).hidden = false;
} }
params.Parameters.forEach((param, index) => { params.Parameters.forEach((param, index) => {
var option = document.createElement("option"); var option = document.createElement("option");
option.text = param.name; option.text = param.name;
option.value = index; option.value = index;
option.setAttribute("data-type",param.type); option.setAttribute("data-type",param.type);
document.getElementById("actParamSelect"+ID).appendChild(option); document.getElementById("actParamSelect"+ID).appendChild(option);
if(param.operators === undefined){ if(param.operators === undefined){
document.getElementById("btnActOperator"+ID).dataset.tglstates = "[\"=\"]"; document.getElementById("btnActOperator"+ID).dataset.tglstates = "[\"=\"]";
document.getElementById("btnActOperator"+ID).innerHTML = "="; document.getElementById("btnActOperator"+ID).innerHTML = "=";
}else{ }else{
document.getElementById("btnActOperator"+ID).dataset.tglstates = JSON.stringify(param.operators); document.getElementById("btnActOperator"+ID).dataset.tglstates = JSON.stringify(param.operators);
document.getElementById("btnActOperator"+ID).innerHTML = param.operators[0]; document.getElementById("btnActOperator"+ID).innerHTML = param.operators[0];
} }
document.getElementById("btnActOperator"+ID).addEventListener("click", tglOperators); document.getElementById("btnActOperator"+ID).addEventListener("click", tglOperators);
if(document.getElementById("btnActLogic"+ID)){ if(document.getElementById("btnActLogic"+ID)){
document.getElementById("btnActLogic"+ID).addEventListener("click", tglOperators); document.getElementById("btnActLogic"+ID).addEventListener("click", tglOperators);
} }
//if(document.getElementById("actParamSelect"+ID).value == param.id) //if(document.getElementById("actParamSelect"+ID).value == param.id)
// document.getElementById("actValue"+ID).setAttribute("type",param.type); // document.getElementById("actValue"+ID).setAttribute("type",param.type);
}); });
document.getElementById("actParamSelect"+ID).dispatchEvent(new Event('change')); document.getElementById("actParamSelect"+ID).dispatchEvent(new Event('change'));
}) })
.catch(error => { .catch(error => {
document.getElementById("actParamSelect"+ID).innerHTML = ""; document.getElementById("actParamSelect"+ID).innerHTML = "";
}); });
} }
function tglOperators(event){ function tglOperators(event){
btn = event.currentTarget; btn = event.currentTarget;
operators = JSON.parse(btn.dataset.tglstates); operators = JSON.parse(btn.dataset.tglstates);
current = btn.innerHTML; current = btn.innerHTML;
btn.innerHTML = operators[(operators.indexOf(current)+1) % operators.length]; btn.innerHTML = operators[(operators.indexOf(current)+1) % operators.length];
} }
function loadAutomatic(params){ function loadAutomatic(params){
if(params.search("action=new")>0){ if(params.search("action=new")>0){
fillSensorDD("1"); fillSensorDD("1");
fillActorDD("1"); fillActorDD("1");
} }
} }
function openAutoActionModal(params) { function openAutoActionModal(params) {
let contentURL = "./ajax/AutoAction.php"+params; let contentURL = "./ajax/AutoAction.php"+params;
if(params.search("action=new")>0) if(params.search("action=new")>0)
document.getElementById("modal-title").innerHTML = "Neue Automatik anlegen"; document.getElementById("modal-title").innerHTML = "Neue Automatik anlegen";
else else
document.getElementById("modal-title").innerHTML = "Automatik Einstellungen"; document.getElementById("modal-title").innerHTML = "Automatik Einstellungen";
modalBodyElement = document.getElementById('modal-body'); modalBodyElement = document.getElementById('modal-body');
modalBodyElement.innerHTML = loadingHTML("Wird geladen..."); modalBodyElement.innerHTML = loadingHTML("Wird geladen...");
document.getElementById("modalSaveBtn").addEventListener("click", submitFormAjax); document.getElementById("modalSaveBtn").addEventListener("click", submitFormAjax);
document.getElementById("modalSaveBtn").contentURL = contentURL; document.getElementById("modalSaveBtn").contentURL = contentURL;
modalEV.show(); modalEV.show();
fetch(contentURL, { fetch(contentURL, {
method: 'GET', method: 'GET',
headers: { headers: {
'X-Requested-From-Modal': 'a', 'X-Requested-From-Modal': 'a',
'Requested-With-Ajax': 'ajax' 'Requested-With-Ajax': 'ajax'
} }
}) })
.then(response => response.text()) .then(response => response.text())
.then(html => { .then(html => {
modalBodyElement.innerHTML = html; modalBodyElement.innerHTML = html;
loadAutomatic(params); loadAutomatic(params);
document.getElementById("btnAddSensor").addEventListener("click", addSensor); document.getElementById("btnAddSensor").addEventListener("click", addSensor);
document.getElementById("btnAddActor").addEventListener("click", addActor); document.getElementById("btnAddActor").addEventListener("click", addActor);
}) })
.catch(error => { .catch(error => {
modalBodyElement.innerHTML += error.message; modalBodyElement.innerHTML += error.message;
}); });
} }

View File

@ -1,236 +1,236 @@
var mqttData = {}; var mqttData = {};
const solarMQTT = { const solarMQTT = {
getMQTT: function () { getMQTT: function () {
const id = Math.random().toString(36).substring(7); const id = Math.random().toString(36).substring(7);
const topic = "#"; const topic = "#";
const connection = "wss://mqtt.nas.el-wa.org:443" const connection = "wss://mqtt.nas.el-wa.org:443"
mqttsolarTreeDone = false; mqttsolarTreeDone = false;
// const connection = "ws://username:password@37.97.203.138:8083" // Works // const connection = "ws://username:password@37.97.203.138:8083" // Works
// const connection = "wss://public:public@public.cloud.shiftr.io" // Works // const connection = "wss://public:public@public.cloud.shiftr.io" // Works
const client = mqtt.connect(connection, { const client = mqtt.connect(connection, {
rejectUnauthorized: false, rejectUnauthorized: false,
}); });
client.on("message", messageReceived); client.on("message", messageReceived);
client.on("connect", function () { client.on("connect", function () {
client.subscribe("solarManager/#"); client.subscribe("solarManager/#");
client.subscribe("wattpilot/properties/lmo/state"); client.subscribe("wattpilot/properties/lmo/state");
client.subscribe("wattpilot/properties/ftt/state"); client.subscribe("wattpilot/properties/ftt/state");
client.subscribe("wattpilot/properties/fte/state"); client.subscribe("wattpilot/properties/fte/state");
client.subscribe("wattpilot/properties/amp/state"); client.subscribe("wattpilot/properties/amp/state");
client.subscribe("wattpilot/properties/car/state"); client.subscribe("wattpilot/properties/car/state");
client.subscribe("go-eCharger/270003/amp"); client.subscribe("go-eCharger/270003/amp");
client.subscribe("go-eCharger/270003/ate"); client.subscribe("go-eCharger/270003/ate");
client.subscribe("go-eCharger/270003/lmo"); client.subscribe("go-eCharger/270003/lmo");
client.subscribe("go-eCharger/270003/att"); client.subscribe("go-eCharger/270003/att");
client.subscribe("go-eCharger/270003/car"); client.subscribe("go-eCharger/270003/car");
client.subscribe("weatherStation/#"); client.subscribe("weatherStation/#");
}); });
client.on("error", function (error) { client.on("error", function (error) {
//alert("MQTT Error: " + error); //alert("MQTT Error: " + error);
}); });
client.on('end', function () { client.on('end', function () {
setTimeout(getMQTT, 5000); setTimeout(getMQTT, 5000);
alert("MQTT Disconnected, try to reconnect in 5 secs."); alert("MQTT Disconnected, try to reconnect in 5 secs.");
}) })
function getNestedProp(obj, path) { function getNestedProp(obj, path) {
return path.split('/').reduce((acc, key) => acc && acc[key], obj); return path.split('/').reduce((acc, key) => acc && acc[key], obj);
} }
function setNestedProp(obj, path, value) { function setNestedProp(obj, path, value) {
var schema = obj; // a moving reference to internal objects within obj var schema = obj; // a moving reference to internal objects within obj
var pList = path.split('/'); var pList = path.split('/');
var len = pList.length; var len = pList.length;
for (var i = 0; i < len - 1; i++) { for (var i = 0; i < len - 1; i++) {
var elem = pList[i]; var elem = pList[i];
if (!schema[elem]) schema[elem] = {} if (!schema[elem]) schema[elem] = {}
schema = schema[elem]; schema = schema[elem];
} }
schema[pList[len - 1]] = value; schema[pList[len - 1]] = value;
} }
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
} }
} }
} }
} }
const solarSVG = { const solarSVG = {
updateCnt: 99, updateCnt: 99,
updateValuesMQTT: function (mqttData) { updateValuesMQTT: function (mqttData) {
if (this.updateCnt > 10) { if (this.updateCnt > 10) {
this.updateCnt = 0; this.updateCnt = 0;
var obj = document.querySelector("object"); var obj = document.querySelector("object");
var htmlNode = obj.contentDocument; var htmlNode = obj.contentDocument;
htmlNode.getElementById("PufferOtxt").innerHTML = mqttData["solarManager"]["t_buffT"] + "°C"; htmlNode.getElementById("PufferOtxt").innerHTML = mqttData["solarManager"]["t_buffT"] + "°C";
htmlNode.getElementById("PufferMtxt").innerHTML = mqttData["solarManager"]["t_buffM"] + "°C"; htmlNode.getElementById("PufferMtxt").innerHTML = mqttData["solarManager"]["t_buffM"] + "°C";
htmlNode.getElementById("PufferUtxt").innerHTML = mqttData["solarManager"]["t_buffB"] + "°C"; htmlNode.getElementById("PufferUtxt").innerHTML = mqttData["solarManager"]["t_buffB"] + "°C";
htmlNode.getElementById("heaterVL").innerHTML = mqttData["solarManager"]["t_heatVL"] + "°C"; htmlNode.getElementById("heaterVL").innerHTML = mqttData["solarManager"]["t_heatVL"] + "°C";
htmlNode.getElementById("heaterRL").innerHTML = mqttData["solarManager"]["t_heatRL"] + "°C"; htmlNode.getElementById("heaterRL").innerHTML = mqttData["solarManager"]["t_heatRL"] + "°C";
htmlNode.getElementById("thermeVLfb").innerHTML = mqttData["solarManager"]["t_gasVLu"] + "°C"; htmlNode.getElementById("thermeVLfb").innerHTML = mqttData["solarManager"]["t_gasVLu"] + "°C";
htmlNode.getElementById("thermeVLww").innerHTML = mqttData["solarManager"]["t_gasVLo"] + "°C"; htmlNode.getElementById("thermeVLww").innerHTML = mqttData["solarManager"]["t_gasVLo"] + "°C";
htmlNode.getElementById("thermeRL").innerHTML = mqttData["solarManager"]["t_gasRL"] + "°C"; htmlNode.getElementById("thermeRL").innerHTML = mqttData["solarManager"]["t_gasRL"] + "°C";
htmlNode.getElementById("fbVL").innerHTML = mqttData["solarManager"]["t_fbVL"] + "°C"; htmlNode.getElementById("fbVL").innerHTML = mqttData["solarManager"]["t_fbVL"] + "°C";
htmlNode.getElementById("fbRL").innerHTML = mqttData["solarManager"]["t_fbRL"] + "°C"; htmlNode.getElementById("fbRL").innerHTML = mqttData["solarManager"]["t_fbRL"] + "°C";
htmlNode.getElementById("triac").innerHTML = mqttData["solarManager"]["t_triac"] + "°C"; htmlNode.getElementById("triac").innerHTML = mqttData["solarManager"]["t_triac"] + "°C";
} }
this.updateCnt++; this.updateCnt++;
} }
} }
var chartSettings = { var chartSettings = {
type: 'line', type: 'line',
options: { options: {
animation: true, animation: true,
plugins: { plugins: {
annotation: { annotation: {
common: { type: 'box', drawTime: 'beforeDatasetsDraw', yScaleID: 'y-axis-0', backgroundColor: 'rgba(255, 255, 255, 0.05)', init: true }, common: { type: 'box', drawTime: 'beforeDatasetsDraw', yScaleID: 'y-axis-0', backgroundColor: 'rgba(255, 255, 255, 0.05)', init: true },
annotations: [] annotations: []
}, },
tooltip: { tooltip: {
position: 'nearest', position: 'nearest',
pointStyle: "circle", pointStyle: "circle",
boxWidth: 4, boxWidth: 4,
usePointStyle: true, usePointStyle: true,
callbacks: { callbacks: {
label: function (context) { label: function (context) {
let label = context.dataset.label || ''; let label = context.dataset.label || '';
if (label) { if (label) {
label += ': '; label += ': ';
} }
if (context.dataset.yAxisID == "y1") { if (context.dataset.yAxisID == "y1") {
label += Math.round(context.parsed.y * 10) / 10 + " " + "L/min"; label += Math.round(context.parsed.y * 10) / 10 + " " + "L/min";
} else { } else {
if (context.parsed.y !== null) { if (context.parsed.y !== null) {
ret = scale(Math.round(context.parsed.y), false); ret = scale(Math.round(context.parsed.y), false);
label += ret[0] + " " + ret[1] + "°C"; label += ret[0] + " " + ret[1] + "°C";
} }
} }
return label; return label;
}, },
}, },
}, },
legend: { legend: {
position: "bottom", position: "bottom",
labels: { labels: {
pointStyleWidth: 10, pointStyleWidth: 10,
usePointStyle: true, usePointStyle: true,
pointStyle: "line", pointStyle: "line",
} }
}, },
}, },
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
interaction: { interaction: {
intersect: false, intersect: false,
mode: 'index', mode: 'index',
}, },
scales: { scales: {
x: { x: {
adapters: { adapters: {
date: { date: {
locale: "DE-de" locale: "DE-de"
} }
}, },
ticks: { ticks: {
}, },
type: 'timestack', type: 'timestack',
}, },
y: { y: {
stacked: false, stacked: false,
display: true, display: true,
position: 'left', position: 'left',
ticks: { ticks: {
callback: value => `${value}°C`, callback: value => `${value}°C`,
}, },
title: { title: {
display: true, display: true,
text: "Temperatur" text: "Temperatur"
} }
}, },
y1: { y1: {
stacked: false, stacked: false,
display: true, display: true,
position: 'right', position: 'right',
ticks: { ticks: {
callback: value => `${value}L/min`, callback: value => `${value}L/min`,
}, },
title: { title: {
display: true, display: true,
text: "Wasserverbrauch" text: "Wasserverbrauch"
}, },
data:{} data:{}
} }
} }
} }
}; };
var chartData = {}; var chartData = {};
const heatChart = new Chart( const heatChart = new Chart(
document.querySelector('#heat-chart'), document.querySelector('#heat-chart'),
Object.assign({}, chartSettings) Object.assign({}, chartSettings)
); );
const waterChart = new Chart( const waterChart = new Chart(
document.querySelector('#water-chart'), document.querySelector('#water-chart'),
Object.assign({}, chartSettings) Object.assign({}, 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');
getData(waterChart, 'ajax/getWaterData.php'); getData(waterChart, 'ajax/getWaterData.php');
} }
}); });
String.prototype.toHHMM = function () { String.prototype.toHHMM = function () {
var sec_num = parseInt(this, 10); // don't forget the second param var sec_num = parseInt(this, 10); // don't forget the second param
var hours = Math.floor(sec_num / 3600); var hours = Math.floor(sec_num / 3600);
var minutes = Math.floor((sec_num - (hours * 3600)) / 60); var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
var seconds = sec_num - (hours * 3600) - (minutes * 60); var seconds = sec_num - (hours * 3600) - (minutes * 60);
if (hours < 10) { hours = "0" + hours; } if (hours < 10) { hours = "0" + hours; }
if (minutes < 10) { minutes = "0" + minutes; } if (minutes < 10) { minutes = "0" + minutes; }
return hours + ':' + minutes; return hours + ':' + minutes;
} }
async function getData(chart, url, sunrise=true) { async function getData(chart, url, sunrise=true) {
try { try {
console.log("fetching"); console.log("fetching");
const response = await fetch(url); const response = await fetch(url);
if (!response.ok) { if (!response.ok) {
console.log("err"); console.log("err");
throw new Error(`Response status: ${response.status}`); throw new Error(`Response status: ${response.status}`);
} }
chart.data = await response.json(); chart.data = await response.json();
if(sunrise){ if(sunrise){
const response2 = await fetch("ajax/getSunrise.php?FROM=-24&TO=0"); const response2 = await fetch("ajax/getSunrise.php?FROM=-24&TO=0");
if (!response2.ok) { if (!response2.ok) {
console.log("err"); console.log("err");
throw new Error(`Response status: ${response2.status}`); throw new Error(`Response status: ${response2.status}`);
} }
chart.options.plugins.annotation.annotations = await response2.json(); chart.options.plugins.annotation.annotations = await response2.json();
} }
chart.update(); chart.update();
} catch (error) { } catch (error) {
console.log(error.message); console.log(error.message);
} }
setTimeout(function () { getData(chart, url, sunrise) }, 5 * 60 * 1000); //renew data every 5 min. setTimeout(function () { getData(chart, url, sunrise) }, 5 * 60 * 1000); //renew data every 5 min.
} }
function powerToString(power) { function powerToString(power) {
if (Math.abs(power) > 999) { if (Math.abs(power) > 999) {
power = power / 1000 power = power / 1000
return power.toPrecision(3) + "kW" return power.toPrecision(3) + "kW"
} else { } else {
return Math.round(power) + "W" return Math.round(power) + "W"
} }
} }

View File

@ -1,199 +1,199 @@
tooltipLabel = function (context) { tooltipLabel = function (context) {
let label = context.dataset.label || ''; let label = context.dataset.label || '';
if (label) { if (label) {
label += ': '; label += ': ';
} }
if (context.dataset.yAxisID == "y1") { if (context.dataset.yAxisID == "y1") {
label += Math.round(context.parsed.y * 10) / 10 + " " + "%"; label += Math.round(context.parsed.y * 10) / 10 + " " + "%";
} else { } else {
if (context.parsed.y !== null) { if (context.parsed.y !== null) {
ret = scale(Math.round(context.parsed.y), false); ret = scale(Math.round(context.parsed.y), false);
label += ret[0] + " " + ret[1] + "Wh"; label += ret[0] + " " + ret[1] + "Wh";
} }
} }
return label; return label;
}; };
tooltipFooter = function (tooltipItems){ tooltipFooter = function (tooltipItems){
let sum = 0; let sum = 0;
tooltipItems.forEach(function(tooltipItem) { tooltipItems.forEach(function(tooltipItem) {
if (tooltipItem.dataset.yAxisID != "y1") { if (tooltipItem.dataset.yAxisID != "y1") {
sum += tooltipItem.parsed.y; sum += tooltipItem.parsed.y;
} }
}); });
ret = scale(Math.round(sum), false); ret = scale(Math.round(sum), false);
sum = ret[0] + " " + ret[1] + "Wh"; sum = ret[0] + " " + ret[1] + "Wh";
return 'Summe: ' + sum; return 'Summe: ' + sum;
} }
legendLabels = function(chart){ legendLabels = function(chart){
const datasets = chart.data.datasets; const datasets = chart.data.datasets;
const { const {
labels: { labels: {
usePointStyle, usePointStyle,
pointStyle, pointStyle,
textAlign, textAlign,
color color
} }
} = chart.legend.options; } = chart.legend.options;
return chart._getSortedDatasetMetas().map((meta) => { return chart._getSortedDatasetMetas().map((meta) => {
const style = meta.controller.getStyle(usePointStyle ? 0 : undefined); const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
const borderWidth = Chart.helpers.toPadding(style.borderWidth); const borderWidth = Chart.helpers.toPadding(style.borderWidth);
ret = scale(Math.round(arraySum(datasets[meta.index].data)), false); ret = scale(Math.round(arraySum(datasets[meta.index].data)), false);
ret2 = scale(Math.round(datasets[meta.index].data[datasets[meta.index].data.length-1]), false); ret2 = scale(Math.round(datasets[meta.index].data[datasets[meta.index].data.length-1]), false);
return { return {
text: datasets[meta.index].label + " Σ " + ret[0]+" "+ret[1]+"Wh",//+ " Last: " + ret2[0]+" "+ret2[1]+"W", text: datasets[meta.index].label + " Σ " + ret[0]+" "+ret[1]+"Wh",//+ " Last: " + ret2[0]+" "+ret2[1]+"W",
fillStyle: style.backgroundColor, fillStyle: style.backgroundColor,
fontColor: color, fontColor: color,
hidden: !meta.visible, hidden: !meta.visible,
lineCap: style.borderCapStyle, lineCap: style.borderCapStyle,
lineDash: style.borderDash, lineDash: style.borderDash,
lineDashOffset: style.borderDashOffset, lineDashOffset: style.borderDashOffset,
lineJoin: style.borderJoinStyle, lineJoin: style.borderJoinStyle,
lineWidth: (borderWidth.width + borderWidth.height) / 4, lineWidth: (borderWidth.width + borderWidth.height) / 4,
strokeStyle: style.borderColor, strokeStyle: style.borderColor,
pointStyle: pointStyle || style.pointStyle, pointStyle: pointStyle || style.pointStyle,
rotation: style.rotation, rotation: style.rotation,
textAlign: textAlign || style.textAlign, textAlign: textAlign || style.textAlign,
borderRadius: 0, // TODO: v4, default to style.borderRadius borderRadius: 0, // TODO: v4, default to style.borderRadius
datasetIndex: meta.index datasetIndex: meta.index
}; };
}, this); }, this);
} }
Chart.defaults.plugins.tooltip.callbacks.footer = tooltipFooter; Chart.defaults.plugins.tooltip.callbacks.footer = tooltipFooter;
Chart.defaults.plugins.tooltip.callbacks.label = tooltipLabel; Chart.defaults.plugins.tooltip.callbacks.label = tooltipLabel;
Chart.defaults.plugins.legend.labels.generateLabels = legendLabels; Chart.defaults.plugins.legend.labels.generateLabels = legendLabels;
var forecastChartSettings = { var forecastChartSettings = {
type: 'bar', type: 'bar',
options: { options: {
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
interaction: { interaction: {
intersect: false, intersect: false,
mode: 'index', mode: 'index',
}, },
scales: { scales: {
y: { y: {
stacked: true, stacked: true,
display: true, display: true,
min: 0, min: 0,
suggestedMax: 1000, suggestedMax: 1000,
ticks: { ticks: {
callback: value => `${value / 1000}kWh`, callback: value => `${value / 1000}kWh`,
} }
}, },
} }
} }
}; };
var decadeChartSettings = { var decadeChartSettings = {
type: 'bar', type: 'bar',
options: { options: {
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
interaction: { interaction: {
intersect: false, intersect: false,
mode: 'index', mode: 'index',
}, },
scales: { scales: {
y: { y: {
stacked: true, stacked: true,
display: true, display: true,
min: 0, min: 0,
suggestedMax: 1000000, suggestedMax: 1000000,
ticks: { ticks: {
callback: value => `${value / 1000000}MWh`, callback: value => `${value / 1000000}MWh`,
} }
}, },
} }
} }
}; };
var chartData = {}; var chartData = {};
const consChart = new Chart( const consChart = new Chart(
document.querySelector('#consumption-chart'), document.querySelector('#consumption-chart'),
Object.assign({}, forecastChartSettings) Object.assign({}, forecastChartSettings)
); );
const prodChart = new Chart( const prodChart = new Chart(
document.querySelector('#production-chart'), document.querySelector('#production-chart'),
Object.assign({}, forecastChartSettings) Object.assign({}, forecastChartSettings)
); );
const consChartYear = new Chart( const consChartYear = new Chart(
document.querySelector('#consumption-chart-year'), document.querySelector('#consumption-chart-year'),
Object.assign({}, decadeChartSettings) Object.assign({}, decadeChartSettings)
); );
const prodChartYear = new Chart( const prodChartYear = new Chart(
document.querySelector('#production-chart-year'), document.querySelector('#production-chart-year'),
Object.assign({}, decadeChartSettings) Object.assign({}, decadeChartSettings)
); );
const consChartDecade = new Chart( const consChartDecade = new Chart(
document.querySelector('#consumption-chart-decade'), document.querySelector('#consumption-chart-decade'),
Object.assign({}, decadeChartSettings) Object.assign({}, decadeChartSettings)
); );
const prodChartDecade = new Chart( const prodChartDecade = new Chart(
document.querySelector('#production-chart-decade'), document.querySelector('#production-chart-decade'),
Object.assign({}, decadeChartSettings) Object.assign({}, decadeChartSettings)
); );
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/getProdData_month.php');
getData(consChart, 'ajax/getConsData_month.php'); getData(consChart, 'ajax/getConsData_month.php');
getData(prodChartYear, 'ajax/getProdData_year.php'); getData(prodChartYear, 'ajax/getProdData_year.php');
getData(consChartYear, 'ajax/getConsData_year.php'); getData(consChartYear, 'ajax/getConsData_year.php');
getData(prodChartDecade, 'ajax/getProdData_decade.php'); getData(prodChartDecade, 'ajax/getProdData_decade.php');
getData(consChartDecade, 'ajax/getConsData_decade.php'); getData(consChartDecade, 'ajax/getConsData_decade.php');
//getData(prodChart, 'ajax/getProdData.php'); //getData(prodChart, 'ajax/getProdData.php');
//getData(foreChart,'ajax/getForecastData.php', false); //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) { async function getData(chart, url, sunrise=true) {
try { try {
console.log("fetching"+chart); console.log("fetching"+chart);
const response = await fetch(url); const response = await fetch(url);
if (!response.ok) { if (!response.ok) {
console.log("err"); console.log("err");
throw new Error(`Response status: ${response.status}`); throw new Error(`Response status: ${response.status}`);
} }
chart.data = await response.json(); chart.data = await response.json();
chart.update(); chart.update();
//chart.options.scales.x.min = chart.data.labels[0]-(chart.data.labels[1]-chart.data.labels[0])/2; //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.options.scales.x.max = chart.data.labels[chart.data.labels.length-1]+(chart.data.labels[1]-chart.data.labels[0])/2;
chart.update(); chart.update();
} catch (error) { } catch (error) {
console.log(error.message); console.log(error.message);
} }
setTimeout(function () { getData(chart, url, sunrise) }, 5 * 60 * 1000); //renew data every 5 min. setTimeout(function () { getData(chart, url, sunrise) }, 5 * 60 * 1000); //renew data every 5 min.
} }
async function getStats(elem_id, url) { async function getStats(elem_id, url) {
try { try {
console.log("fetching"); console.log("fetching");
const response = await fetch(url); const response = await fetch(url);
if (!response.ok) { if (!response.ok) {
console.log("err"); console.log("err");
throw new Error(`Response status: ${response.status}`); throw new Error(`Response status: ${response.status}`);
} }
document.getElementById(elem_id).innerHTML = await response.text(); document.getElementById(elem_id).innerHTML = await response.text();
} catch (error) { } catch (error) {
console.log(error.message); console.log(error.message);
} }
setTimeout(function () { getData(chart, url, sunrise) }, 5 * 60 * 1000); //renew data every 5 min. setTimeout(function () { getData(chart, url, sunrise) }, 5 * 60 * 1000); //renew data every 5 min.
} }
function powerToString(power) { function powerToString(power) {
if (Math.abs(power) > 999) { if (Math.abs(power) > 999) {
power = power / 1000 power = power / 1000
return power.toPrecision(3) + "kW" return power.toPrecision(3) + "kW"
} else { } else {
return Math.round(power) + "W" return Math.round(power) + "W"
} }
} }

View File

@ -1,427 +1,427 @@
const homeMQTT = { const homeMQTT = {
getMQTT: function () { getMQTT: function () {
const id = Math.random().toString(36).substring(7); const id = Math.random().toString(36).substring(7);
const topic = "#"; const topic = "#";
const connection = "wss://mqtt.nas.el-wa.org:443" const connection = "wss://mqtt.nas.el-wa.org:443"
mqttsolarTreeDone = false; mqttsolarTreeDone = false;
// const connection = "ws://username:password@37.97.203.138:8083" // Works // const connection = "ws://username:password@37.97.203.138:8083" // Works
// const connection = "wss://public:public@public.cloud.shiftr.io" // Works // const connection = "wss://public:public@public.cloud.shiftr.io" // Works
const client = mqtt.connect(connection, { const client = mqtt.connect(connection, {
rejectUnauthorized: false, rejectUnauthorized: false,
}); });
client.on("message", messageReceived); client.on("message", messageReceived);
client.on("connect", function () { client.on("connect", function () {
client.subscribe("Raumtemp/#"); client.subscribe("Raumtemp/#");
}); });
client.on("error", function (error) { client.on("error", function (error) {
//alert("MQTT Error: " + error); //alert("MQTT Error: " + error);
}); });
client.on('end', function () { client.on('end', function () {
setTimeout(getMQTT, 5000); setTimeout(getMQTT, 5000);
alert("MQTT Disconnected, try to reconnect in 5 secs."); alert("MQTT Disconnected, try to reconnect in 5 secs.");
}) })
function getNestedProp(obj, path) { function getNestedProp(obj, path) {
return path.split('/').reduce((acc, key) => acc && acc[key], obj); return path.split('/').reduce((acc, key) => acc && acc[key], obj);
} }
function setNestedProp(obj, path, value) { function setNestedProp(obj, path, value) {
var schema = obj; // a moving reference to internal objects within obj var schema = obj; // a moving reference to internal objects within obj
var pList = path.split('/'); var pList = path.split('/');
var len = pList.length; var len = pList.length;
for (var i = 0; i < len - 1; i++) { for (var i = 0; i < len - 1; i++) {
var elem = pList[i]; var elem = pList[i];
if (!schema[elem]) schema[elem] = {} if (!schema[elem]) schema[elem] = {}
schema = schema[elem]; schema = schema[elem];
} }
schema[pList[len - 1]] = value; schema[pList[len - 1]] = value;
} }
function messageReceived(topic, message) { function messageReceived(topic, message) {
setNestedProp(mqttData, topic, message); setNestedProp(mqttData, topic, message);
setTimeout(function () { homeSVG.updateValuesMQTT(mqttData) }, 200); //give the object tree some time to build up and receive all values setTimeout(function () { homeSVG.updateValuesMQTT(mqttData) }, 200); //give the object tree some time to build up and receive all values
} }
} }
} }
const homeSVG = { const homeSVG = {
updateCnt: 99, updateCnt: 99,
fillElementArray: function () { fillElementArray: function () {
}, },
updateValuesMQTT: function (mqttData) { updateValuesMQTT: function (mqttData) {
var htmlNode = document var htmlNode = document
//OG //OG
if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Heating"] == "false") htmlNode.getElementById('OG_wozi_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Heating"] == "false") htmlNode.getElementById('OG_wozi_heater').setAttribute("display", "none");
else htmlNode.getElementById('OG_wozi_heater').setAttribute("display", ""); else htmlNode.getElementById('OG_wozi_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["mode"] == "Overheating") htmlNode.getElementById('OG_wozi_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["mode"] == "Overheating") htmlNode.getElementById('OG_wozi_buffer').setAttribute("display", "");
else htmlNode.getElementById('OG_wozi_buffer').setAttribute("display", "none"); else htmlNode.getElementById('OG_wozi_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Set Temp[degC]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Set Temp[degC]"]) != "undefined")
htmlNode.getElementById('OG_pres_wozi').innerHTML = Math.floor(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Set Temp[degC]"])+"°C"; htmlNode.getElementById('OG_pres_wozi').innerHTML = Math.floor(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Set Temp[degC]"])+"°C";
if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Temp[degC]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('OG_tmp_wozi').innerHTML = mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Temp[degC]"]+"°C"; htmlNode.getElementById('OG_tmp_wozi').innerHTML = mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('OG_hum_wozi').innerHTML = mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["rHum[%]"]+"%rF"; htmlNode.getElementById('OG_hum_wozi').innerHTML = mqttData["Raumtemp"]["OG"]["Wohnzimmer"]["rHum[%]"]+"%rF";
if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["OG"]["Bad"]["Heating"] == "false") htmlNode.getElementById('OG_bad_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["OG"]["Bad"]["Heating"] == "false") htmlNode.getElementById('OG_bad_heater').setAttribute("display", "none");
else htmlNode.getElementById('OG_bad_heater').setAttribute("display", ""); else htmlNode.getElementById('OG_bad_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["OG"]["Bad"]["mode"] == "Overheating") htmlNode.getElementById('OG_bad_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["OG"]["Bad"]["mode"] == "Overheating") htmlNode.getElementById('OG_bad_buffer').setAttribute("display", "");
else htmlNode.getElementById('OG_bad_buffer').setAttribute("display", "none"); else htmlNode.getElementById('OG_bad_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('OG_tmp_bad').innerHTML = mqttData["Raumtemp"]["OG"]["Bad"]["Temp[degC]"]+"°C"; htmlNode.getElementById('OG_tmp_bad').innerHTML = mqttData["Raumtemp"]["OG"]["Bad"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["OG"]["Bad"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('OG_hum_bad').innerHTML = mqttData["Raumtemp"]["OG"]["Bad"]["rHum[%]"]+"%rF"; htmlNode.getElementById('OG_hum_bad').innerHTML = mqttData["Raumtemp"]["OG"]["Bad"]["rHum[%]"]+"%rF";
if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Heating"] == "false") htmlNode.getElementById('OG_schlafen_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Heating"] == "false") htmlNode.getElementById('OG_schlafen_heater').setAttribute("display", "none");
else htmlNode.getElementById('OG_schlafen_heater').setAttribute("display", ""); else htmlNode.getElementById('OG_schlafen_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["mode"] == "Overheating") htmlNode.getElementById('OG_schlafen_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["mode"] == "Overheating") htmlNode.getElementById('OG_schlafen_buffer').setAttribute("display", "");
else htmlNode.getElementById('OG_schlafen_buffer').setAttribute("display", "none"); else htmlNode.getElementById('OG_schlafen_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('OG_tmp_schlafen').innerHTML = mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Temp[degC]"]+"°C"; htmlNode.getElementById('OG_tmp_schlafen').innerHTML = mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('OG_hum_schlafen').innerHTML = mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["rHum[%]"]+"%rF"; htmlNode.getElementById('OG_hum_schlafen').innerHTML = mqttData["Raumtemp"]["OG"]["Schlafzimmer"]["rHum[%]"]+"%rF";
if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["OG"]["KiZi"]["Heating"] == "false") htmlNode.getElementById('OG_kizi_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["OG"]["KiZi"]["Heating"] == "false") htmlNode.getElementById('OG_kizi_heater').setAttribute("display", "none");
else htmlNode.getElementById('OG_kizi_heater').setAttribute("display", ""); else htmlNode.getElementById('OG_kizi_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["OG"]["KiZi"]["mode"] == "Overheating") htmlNode.getElementById('OG_kizi_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["OG"]["KiZi"]["mode"] == "Overheating") htmlNode.getElementById('OG_kizi_buffer').setAttribute("display", "");
else htmlNode.getElementById('OG_kizi_buffer').setAttribute("display", "none"); else htmlNode.getElementById('OG_kizi_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('OG_tmp_kizi').innerHTML = mqttData["Raumtemp"]["OG"]["KiZi"]["Temp[degC]"]+"°C"; htmlNode.getElementById('OG_tmp_kizi').innerHTML = mqttData["Raumtemp"]["OG"]["KiZi"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["OG"]["KiZi"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('OG_hum_kizi').innerHTML = mqttData["Raumtemp"]["OG"]["KiZi"]["rHum[%]"]+"%rF"; htmlNode.getElementById('OG_hum_kizi').innerHTML = mqttData["Raumtemp"]["OG"]["KiZi"]["rHum[%]"]+"%rF";
if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["OG"]["Buero"]["Heating"] == "false") htmlNode.getElementById('OG_buero_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["OG"]["Buero"]["Heating"] == "false") htmlNode.getElementById('OG_buero_heater').setAttribute("display", "none");
else htmlNode.getElementById('OG_buero_heater').setAttribute("display", ""); else htmlNode.getElementById('OG_buero_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["OG"]["Buero"]["mode"] == "Overheating") htmlNode.getElementById('OG_buero_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["OG"]["Buero"]["mode"] == "Overheating") htmlNode.getElementById('OG_buero_buffer').setAttribute("display", "");
else htmlNode.getElementById('OG_buero_buffer').setAttribute("display", "none"); else htmlNode.getElementById('OG_buero_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('OG_tmp_buero').innerHTML = mqttData["Raumtemp"]["OG"]["Buero"]["Temp[degC]"]+"°C"; htmlNode.getElementById('OG_tmp_buero').innerHTML = mqttData["Raumtemp"]["OG"]["Buero"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["OG"]["Buero"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('OG_hum_buero').innerHTML = mqttData["Raumtemp"]["OG"]["Buero"]["rHum[%]"]+"%rF"; htmlNode.getElementById('OG_hum_buero').innerHTML = mqttData["Raumtemp"]["OG"]["Buero"]["rHum[%]"]+"%rF";
//EG //EG
if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Heating"] == "false") htmlNode.getElementById('EG_wozi_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Heating"] == "false") htmlNode.getElementById('EG_wozi_heater').setAttribute("display", "none");
else htmlNode.getElementById('EG_wozi_heater').setAttribute("display", ""); else htmlNode.getElementById('EG_wozi_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["mode"] == "Overheating") htmlNode.getElementById('EG_wozi_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["mode"] == "Overheating") htmlNode.getElementById('EG_wozi_buffer').setAttribute("display", "");
else htmlNode.getElementById('EG_wozi_buffer').setAttribute("display", "none"); else htmlNode.getElementById('EG_wozi_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('EG_tmp_wozi').innerHTML = mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Temp[degC]"]+"°C"; htmlNode.getElementById('EG_tmp_wozi').innerHTML = mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('EG_hum_wozi').innerHTML = mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["rHum[%]"]+"%rF"; htmlNode.getElementById('EG_hum_wozi').innerHTML = mqttData["Raumtemp"]["EG"]["Wohnzimmer"]["rHum[%]"]+"%rF";
if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["EG"]["Bad"]["Heating"] == "false") htmlNode.getElementById('EG_bad_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["EG"]["Bad"]["Heating"] == "false") htmlNode.getElementById('EG_bad_heater').setAttribute("display", "none");
else htmlNode.getElementById('EG_bad_heater').setAttribute("display", ""); else htmlNode.getElementById('EG_bad_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["EG"]["Bad"]["mode"] == "Overheating") htmlNode.getElementById('EG_bad_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["EG"]["Bad"]["mode"] == "Overheating") htmlNode.getElementById('EG_bad_buffer').setAttribute("display", "");
else htmlNode.getElementById('EG_bad_buffer').setAttribute("display", "none"); else htmlNode.getElementById('EG_bad_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('EG_tmp_bad').innerHTML = mqttData["Raumtemp"]["EG"]["Bad"]["Temp[degC]"]+"°C"; htmlNode.getElementById('EG_tmp_bad').innerHTML = mqttData["Raumtemp"]["EG"]["Bad"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["EG"]["Bad"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('EG_hum_bad').innerHTML = mqttData["Raumtemp"]["EG"]["Bad"]["rHum[%]"]+"%rF"; htmlNode.getElementById('EG_hum_bad').innerHTML = mqttData["Raumtemp"]["EG"]["Bad"]["rHum[%]"]+"%rF";
if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["EG"]["Schlafen"]["Heating"] == "false") htmlNode.getElementById('EG_schlafen_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["EG"]["Schlafen"]["Heating"] == "false") htmlNode.getElementById('EG_schlafen_heater').setAttribute("display", "none");
else htmlNode.getElementById('EG_schlafen_heater').setAttribute("display", ""); else htmlNode.getElementById('EG_schlafen_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["EG"]["Schlafen"]["mode"] == "Overheating") htmlNode.getElementById('EG_schlafen_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["EG"]["Schlafen"]["mode"] == "Overheating") htmlNode.getElementById('EG_schlafen_buffer').setAttribute("display", "");
else htmlNode.getElementById('EG_schlafen_buffer').setAttribute("display", "none"); else htmlNode.getElementById('EG_schlafen_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('EG_tmp_schlafen').innerHTML = mqttData["Raumtemp"]["EG"]["Schlafen"]["Temp[degC]"]+"°C"; htmlNode.getElementById('EG_tmp_schlafen').innerHTML = mqttData["Raumtemp"]["EG"]["Schlafen"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["EG"]["Schlafen"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('EG_hum_schlafen').innerHTML = mqttData["Raumtemp"]["EG"]["Schlafen"]["rHum[%]"]+"%rF"; htmlNode.getElementById('EG_hum_schlafen').innerHTML = mqttData["Raumtemp"]["EG"]["Schlafen"]["rHum[%]"]+"%rF";
if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["EG"]["Florian"]["Heating"] == "false") htmlNode.getElementById('EG_kizi_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["EG"]["Florian"]["Heating"] == "false") htmlNode.getElementById('EG_kizi_heater').setAttribute("display", "none");
else htmlNode.getElementById('EG_kizi_heater').setAttribute("display", ""); else htmlNode.getElementById('EG_kizi_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["EG"]["Florian"]["mode"] == "Overheating") htmlNode.getElementById('EG_kizi_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["EG"]["Florian"]["mode"] == "Overheating") htmlNode.getElementById('EG_kizi_buffer').setAttribute("display", "");
else htmlNode.getElementById('EG_kizi_buffer').setAttribute("display", "none"); else htmlNode.getElementById('EG_kizi_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('EG_tmp_kizi').innerHTML = mqttData["Raumtemp"]["EG"]["Florian"]["Temp[degC]"]+"°C"; htmlNode.getElementById('EG_tmp_kizi').innerHTML = mqttData["Raumtemp"]["EG"]["Florian"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["EG"]["Florian"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('EG_hum_kizi').innerHTML = mqttData["Raumtemp"]["EG"]["Florian"]["rHum[%]"]+"%rF"; htmlNode.getElementById('EG_hum_kizi').innerHTML = mqttData["Raumtemp"]["EG"]["Florian"]["rHum[%]"]+"%rF";
if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["EG"]["Magdalena"]["Heating"] == "false") htmlNode.getElementById('EG_buero_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["EG"]["Magdalena"]["Heating"] == "false") htmlNode.getElementById('EG_buero_heater').setAttribute("display", "none");
else htmlNode.getElementById('EG_buero_heater').setAttribute("display", ""); else htmlNode.getElementById('EG_buero_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["EG"]["Magdalena"]["mode"] == "Overheating") htmlNode.getElementById('EG_buero_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["EG"]["Magdalena"]["mode"] == "Overheating") htmlNode.getElementById('EG_buero_buffer').setAttribute("display", "");
else htmlNode.getElementById('EG_buero_buffer').setAttribute("display", "none"); else htmlNode.getElementById('EG_buero_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('EG_tmp_buero').innerHTML = mqttData["Raumtemp"]["EG"]["Magdalena"]["Temp[degC]"]+"°C"; htmlNode.getElementById('EG_tmp_buero').innerHTML = mqttData["Raumtemp"]["EG"]["Magdalena"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["EG"]["Magdalena"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('EG_hum_buero').innerHTML = mqttData["Raumtemp"]["EG"]["Magdalena"]["rHum[%]"]+"%rF"; htmlNode.getElementById('EG_hum_buero').innerHTML = mqttData["Raumtemp"]["EG"]["Magdalena"]["rHum[%]"]+"%rF";
//UG //UG
if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["UG"]["Kueche"]["Heating"] == "false") htmlNode.getElementById('UG_kueche_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["UG"]["Kueche"]["Heating"] == "false") htmlNode.getElementById('UG_kueche_heater').setAttribute("display", "none");
else htmlNode.getElementById('UG_kueche_heater').setAttribute("display", ""); else htmlNode.getElementById('UG_kueche_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["UG"]["Kueche"]["mode"] == "Overheating") htmlNode.getElementById('UG_kueche_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["UG"]["Kueche"]["mode"] == "Overheating") htmlNode.getElementById('UG_kueche_buffer').setAttribute("display", "");
else htmlNode.getElementById('UG_kueche_buffer').setAttribute("display", "none"); else htmlNode.getElementById('UG_kueche_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('UG_tmp_kueche').innerHTML = mqttData["Raumtemp"]["UG"]["Kueche"]["Temp[degC]"]+"°C"; htmlNode.getElementById('UG_tmp_kueche').innerHTML = mqttData["Raumtemp"]["UG"]["Kueche"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["UG"]["Kueche"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('UG_hum_kueche').innerHTML = mqttData["Raumtemp"]["UG"]["Kueche"]["rHum[%]"]+"%rF"; htmlNode.getElementById('UG_hum_kueche').innerHTML = mqttData["Raumtemp"]["UG"]["Kueche"]["rHum[%]"]+"%rF";
if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["UG"]["Buero"]["Heating"] == "false") htmlNode.getElementById('UG_buero_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["UG"]["Buero"]["Heating"] == "false") htmlNode.getElementById('UG_buero_heater').setAttribute("display", "none");
else htmlNode.getElementById('UG_buero_heater').setAttribute("display", ""); else htmlNode.getElementById('UG_buero_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["UG"]["Buero"]["mode"] == "Overheating") htmlNode.getElementById('UG_buero_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["UG"]["Buero"]["mode"] == "Overheating") htmlNode.getElementById('UG_buero_buffer').setAttribute("display", "");
else htmlNode.getElementById('UG_buero_buffer').setAttribute("display", "none"); else htmlNode.getElementById('UG_buero_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('UG_tmp_buero').innerHTML = mqttData["Raumtemp"]["UG"]["Buero"]["Temp[degC]"]+"°C"; htmlNode.getElementById('UG_tmp_buero').innerHTML = mqttData["Raumtemp"]["UG"]["Buero"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["UG"]["Buero"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('UG_hum_buero').innerHTML = mqttData["Raumtemp"]["UG"]["Buero"]["rHum[%]"]+"%rF"; htmlNode.getElementById('UG_hum_buero').innerHTML = mqttData["Raumtemp"]["UG"]["Buero"]["rHum[%]"]+"%rF";
if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["Heating"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["Heating"]) != "undefined"){
if(mqttData["Raumtemp"]["UG"]["Bad"]["Heating"] == "false") htmlNode.getElementById('UG_bad_heater').setAttribute("display", "none"); if(mqttData["Raumtemp"]["UG"]["Bad"]["Heating"] == "false") htmlNode.getElementById('UG_bad_heater').setAttribute("display", "none");
else htmlNode.getElementById('UG_bad_heater').setAttribute("display", ""); else htmlNode.getElementById('UG_bad_heater').setAttribute("display", "");
} }
if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["mode"]) != "undefined"){ if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["mode"]) != "undefined"){
if(mqttData["Raumtemp"]["UG"]["Bad"]["mode"] == "Overheating") htmlNode.getElementById('UG_bad_buffer').setAttribute("display", ""); if(mqttData["Raumtemp"]["UG"]["Bad"]["mode"] == "Overheating") htmlNode.getElementById('UG_bad_buffer').setAttribute("display", "");
else htmlNode.getElementById('UG_bad_buffer').setAttribute("display", "none"); else htmlNode.getElementById('UG_bad_buffer').setAttribute("display", "none");
} }
if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["Set Temp[degC]"]) != "undefined") 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"; 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") if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["Temp[degC]"]) != "undefined")
htmlNode.getElementById('UG_tmp_bad').innerHTML = mqttData["Raumtemp"]["UG"]["Bad"]["Temp[degC]"]+"°C"; htmlNode.getElementById('UG_tmp_bad').innerHTML = mqttData["Raumtemp"]["UG"]["Bad"]["Temp[degC]"]+"°C";
if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["rHum[%]"]) != "undefined") if(typeof(mqttData["Raumtemp"]["UG"]["Bad"]["rHum[%]"]) != "undefined")
htmlNode.getElementById('UG_hum_bad').innerHTML = mqttData["Raumtemp"]["UG"]["Bad"]["rHum[%]"]+"%rF"; htmlNode.getElementById('UG_hum_bad').innerHTML = mqttData["Raumtemp"]["UG"]["Bad"]["rHum[%]"]+"%rF";
} }
} }
var currentFloor = "OG"; var currentFloor = "OG";
function addClass(el, classNameToAdd){ function addClass(el, classNameToAdd){
el.className += ' ' + classNameToAdd; el.className += ' ' + classNameToAdd;
} }
function removeClass(el, classNameToRemove){ function removeClass(el, classNameToRemove){
var elClass = ' ' + el.className + ' '; var elClass = ' ' + el.className + ' ';
while(elClass.indexOf(' ' + classNameToRemove + ' ') !== -1){ while(elClass.indexOf(' ' + classNameToRemove + ' ') !== -1){
elClass = elClass.replace(' ' + classNameToRemove + ' ', ''); elClass = elClass.replace(' ' + classNameToRemove + ' ', '');
} }
el.className = elClass; el.className = elClass;
} }
function switchTab(newtab){ function switchTab(newtab){
newContent = document.getElementById(newtab); newContent = document.getElementById(newtab);
newTabBtn = document.getElementById(newtab+"-tab"); newTabBtn = document.getElementById(newtab+"-tab");
removeClass(document.getElementById("actions-OG-tab"),"active"); removeClass(document.getElementById("actions-OG-tab"),"active");
removeClass(document.getElementById("actions-EG-tab"),"active"); removeClass(document.getElementById("actions-EG-tab"),"active");
removeClass(document.getElementById("actions-UG-tab"),"active"); removeClass(document.getElementById("actions-UG-tab"),"active");
removeClass(document.getElementById("actions-OG"),"active show"); removeClass(document.getElementById("actions-OG"),"active show");
removeClass(document.getElementById("actions-EG"),"active show"); removeClass(document.getElementById("actions-EG"),"active show");
removeClass(document.getElementById("actions-UG"),"active show"); removeClass(document.getElementById("actions-UG"),"active show");
addClass(newTabBtn,"active"); addClass(newTabBtn,"active");
addClass(newContent,"active show"); addClass(newContent,"active show");
} }
function switchFloor(floor){ function switchFloor(floor){
if(currentFloor == floor) if(currentFloor == floor)
return; return;
const targetIn = document.getElementById(floor+'_Info'); const targetIn = document.getElementById(floor+'_Info');
const targetOut = document.getElementById(currentFloor+'_Info'); const targetOut = document.getElementById(currentFloor+'_Info');
var blendIn = new KeyframeEffect( var blendIn = new KeyframeEffect(
targetIn, [{opacity: '0'},{opacity: '100'}], targetIn, [{opacity: '0'},{opacity: '100'}],
{ {
duration: 500, duration: 500,
easing: "ease-in-out", easing: "ease-in-out",
fill: "forwards", fill: "forwards",
iterations: 1, iterations: 1,
} }
); );
var blendOut = new KeyframeEffect( var blendOut = new KeyframeEffect(
targetOut, [{opacity: '100'},{opacity: '0'}], targetOut, [{opacity: '100'},{opacity: '0'}],
{ {
duration: 500, duration: 500,
easing: "ease-in-out", easing: "ease-in-out",
fill: "forwards", fill: "forwards",
iterations: 1, iterations: 1,
} }
); );
var inAnim = new Animation(blendIn,document.timeline); var inAnim = new Animation(blendIn,document.timeline);
var outAnim = new Animation(blendOut,document.timeline); var outAnim = new Animation(blendOut,document.timeline);
targetIn.setAttribute("display",""); targetIn.setAttribute("display","");
outAnim.onfinish= (event) => { outAnim.onfinish= (event) => {
targetOut.setAttribute("display","none"); targetOut.setAttribute("display","none");
}; };
inAnim.play(); inAnim.play();
outAnim.play(); outAnim.play();
currentFloor = floor; currentFloor = floor;
} }
var modalEV = new bootstrap.Modal(document.getElementById('modalEV'), { var modalEV = new bootstrap.Modal(document.getElementById('modalEV'), {
keyboard: false keyboard: false
}); });
var offcanvas = new bootstrap.Offcanvas(document.getElementById('offcanvas'), { var offcanvas = new bootstrap.Offcanvas(document.getElementById('offcanvas'), {
keyboard: false keyboard: false
}); });
var mqttData = {}; var mqttData = {};
function openHeaterSettings(heater){ function openHeaterSettings(heater){
openModal(heater) openModal(heater)
} }
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>"; 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>";
} }
}); });
function loadingHTML(msg) { function loadingHTML(msg) {
return "<div class='m-4'><div class='spinner-border' role='status'><span class='visually-hidden'>Loading...</span></div>&nbsp;&nbsp;&nbsp;" + msg + "</div>" return "<div class='m-4'><div class='spinner-border' role='status'><span class='visually-hidden'>Loading...</span></div>&nbsp;&nbsp;&nbsp;" + msg + "</div>"
} }
function openModal(heater) { function openModal(heater) {
var contentURL = "./ajax/roomtemp.php?heater="+heater; var contentURL = "./ajax/roomtemp.php?heater="+heater;
let heaterMQTT = heater.toString().split("_"); let heaterMQTT = heater.toString().split("_");
document.getElementById("modal-title").innerHTML = "Thermostat "+heater.replace("_"," ").replace("ue","ü").replace("ae","ä").replace("oe","ö"); document.getElementById("modal-title").innerHTML = "Thermostat "+heater.replace("_"," ").replace("ue","ü").replace("ae","ä").replace("oe","ö");
modalBodyElement = document.getElementById("modal-body"); modalBodyElement = document.getElementById("modal-body");
modalBodyElement.innerHTML = loadingHTML("Wird geladen..."); modalBodyElement.innerHTML = loadingHTML("Wird geladen...");
document.getElementById("modalSaveBtn").addEventListener("click", submitFormAjax); document.getElementById("modalSaveBtn").addEventListener("click", submitFormAjax);
document.getElementById("modalSaveBtn").contentURL = contentURL; document.getElementById("modalSaveBtn").contentURL = contentURL;
modalEV.show(); modalEV.show();
fetch(contentURL, { fetch(contentURL, {
method: 'GET', method: 'GET',
headers: { headers: {
'X-Requested-From-Modal': 'a', 'X-Requested-From-Modal': 'a',
'Requested-With-Ajax': 'ajax' 'Requested-With-Ajax': 'ajax'
} }
}) })
.then(response => response.text()) .then(response => response.text())
.then(html => { .then(html => {
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 () { slider.oninput = function () {
sliderPrcnt=(slider.value-10)*5; sliderPrcnt=(slider.value-10)*5;
slider.style.setProperty("--background-size", `${sliderPrcnt}%`); slider.style.setProperty("--background-size", `${sliderPrcnt}%`);
marginValue = sliderPrcnt; marginValue = sliderPrcnt;
if (marginValue < 10) { if (marginValue < 10) {
marginValue = marginValue - 0.4 * marginValue; marginValue = marginValue - 0.4 * marginValue;
} else if (marginValue < 85) { } else if (marginValue < 85) {
marginValue = marginValue - 4; marginValue = marginValue - 4;
} }
else { else {
marginValue = marginValue - 4 - 0.5 * (marginValue - 85); marginValue = marginValue - 4 - 0.5 * (marginValue - 85);
} }
span.setAttribute('style', 'margin-left:' + marginValue + '%;'); span.setAttribute('style', 'margin-left:' + marginValue + '%;');
span.innerHTML = this.value + " °C"; 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]"]);
else else
slider.setAttribute("value",10); slider.setAttribute("value",10);
slider.dispatchEvent(new Event('input')); slider.dispatchEvent(new Event('input'));
}) })
.catch(error => { .catch(error => {
modalBodyElement.innerHTML += error.message; modalBodyElement.innerHTML += error.message;
}); });
} }
function submitFormAjax(event) { function submitFormAjax(event) {
let xmlhttp = window.XMLHttpRequest ? let xmlhttp = window.XMLHttpRequest ?
new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"); new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange = function () { xmlhttp.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200){ if (this.readyState === 4 && this.status === 200){
setTimeout(function () { modalEV.hide() }, 700); setTimeout(function () { modalEV.hide() }, 700);
alert(xmlhttp.responseText); alert(xmlhttp.responseText);
} }
} }
const form = document.getElementById('modalEV').querySelector('form'); const form = document.getElementById('modalEV').querySelector('form');
post = ""; post = "";
// Get interesting form elements // Get interesting form elements
const formElements = Array.from(form.elements); const formElements = Array.from(form.elements);
for (let i = 0; i < formElements.length; i++) { for (let i = 0; i < formElements.length; i++) {
if(formElements[i].name){ if(formElements[i].name){
if (formElements[i].type == "radio" && formElements[i].checked) { if (formElements[i].type == "radio" && formElements[i].checked) {
post += formElements[i].name + "=" + encodeURIComponent(formElements[i].value) + "&"; post += formElements[i].name + "=" + encodeURIComponent(formElements[i].value) + "&";
} else if(formElements[i].type == "checkbox" && formElements[i].checked){ } else if(formElements[i].type == "checkbox" && formElements[i].checked){
post += formElements[i].name + "=" + encodeURIComponent(formElements[i].value) + "&"; post += formElements[i].name + "=" + encodeURIComponent(formElements[i].value) + "&";
} else if(formElements[i].type == "button" && !formElements[i].classList.contains("accordion-button")){ } else if(formElements[i].type == "button" && !formElements[i].classList.contains("accordion-button")){
post += formElements[i].name + "=" + encodeURIComponent(formElements[i].innerHTML) + "&"; post += formElements[i].name + "=" + encodeURIComponent(formElements[i].innerHTML) + "&";
}else if(formElements[i].type != "checkbox" && formElements[i].type != "radio") { }else if(formElements[i].type != "checkbox" && formElements[i].type != "radio") {
post += formElements[i].name + "=" + encodeURIComponent(formElements[i].value) + "&"; post += formElements[i].name + "=" + encodeURIComponent(formElements[i].value) + "&";
} }
} }
} }
xmlhttp.open("POST", event.currentTarget.contentURL, true); xmlhttp.open("POST", event.currentTarget.contentURL, true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
document.getElementById('modalEV').querySelector('.modal-body').innerHTML = loadingHTML("Änderungen werden übernommen..."); document.getElementById('modalEV').querySelector('.modal-body').innerHTML = loadingHTML("Änderungen werden übernommen...");
xmlhttp.send(post); xmlhttp.send(post);
return false; return false;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
# Netbeans project # Netbeans project
nbproject/ nbproject/
/index.php /index.php
# .pem files from FIDO Alliance Metadata Service (MDS) # .pem files from FIDO Alliance Metadata Service (MDS)
_test/rootCertificates/mds/*.pem _test/rootCertificates/mds/*.pem
_test/rootCertificates/mds/lastMdsFetch.txt _test/rootCertificates/mds/lastMdsFetch.txt

View File

@ -1,22 +1,22 @@
MIT License MIT License
Copyright © 2022 Lukas Buchs Copyright © 2022 Lukas Buchs
Copyright © 2018 Thomas Bleeker (CBOR & ByteBuffer part) Copyright © 2018 Thomas Bleeker (CBOR & ByteBuffer part)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

View File

@ -1,144 +1,144 @@
[![Licensed under the MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/lbuchs/WebAuthn/blob/master/LICENSE) [![Licensed under the MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/lbuchs/WebAuthn/blob/master/LICENSE)
[![Requires PHP 7.1.0](https://img.shields.io/badge/PHP-7.1.0-green.svg)](https://php.net) [![Requires PHP 7.1.0](https://img.shields.io/badge/PHP-7.1.0-green.svg)](https://php.net)
[![Last Commit](https://img.shields.io/github/last-commit/lbuchs/WebAuthn.svg)](https://github.com/lbuchs/WebAuthn/commits/master) [![Last Commit](https://img.shields.io/github/last-commit/lbuchs/WebAuthn.svg)](https://github.com/lbuchs/WebAuthn/commits/master)
# WebAuthn # WebAuthn
*A simple PHP WebAuthn (FIDO2) server library* *A simple PHP WebAuthn (FIDO2) server library*
Goal of this project is to provide a small, lightweight, understandable library to protect logins with passkeys, security keys like Yubico or Solo, fingerprint on Android or Windows Hello. Goal of this project is to provide a small, lightweight, understandable library to protect logins with passkeys, security keys like Yubico or Solo, fingerprint on Android or Windows Hello.
## Manual ## Manual
See /_test for a simple usage of this library. Check [webauthn.lubu.ch](https://webauthn.lubu.ch) for a working example. See /_test for a simple usage of this library. Check [webauthn.lubu.ch](https://webauthn.lubu.ch) for a working example.
### Supported attestation statement formats ### Supported attestation statement formats
* android-key &#x2705; * android-key &#x2705;
* android-safetynet &#x2705; * android-safetynet &#x2705;
* apple &#x2705; * apple &#x2705;
* fido-u2f &#x2705; * fido-u2f &#x2705;
* none &#x2705; * none &#x2705;
* packed &#x2705; * packed &#x2705;
* tpm &#x2705; * tpm &#x2705;
> [!NOTE] > [!NOTE]
> This library supports authenticators which are signed with a X.509 certificate or which are self attested. ECDAA is not supported. > This library supports authenticators which are signed with a X.509 certificate or which are self attested. ECDAA is not supported.
## Workflow ## Workflow
JAVASCRIPT | SERVER JAVASCRIPT | SERVER
------------------------------------------------------------ ------------------------------------------------------------
REGISTRATION REGISTRATION
window.fetch -----------------> getCreateArgs window.fetch -----------------> getCreateArgs
| |
navigator.credentials.create <-------------' navigator.credentials.create <-------------'
| |
'-------------------------> processCreate '-------------------------> processCreate
| |
alert ok or fail <----------------' alert ok or fail <----------------'
------------------------------------------------------------ ------------------------------------------------------------
VALIDATION VALIDATION
window.fetch ------------------> getGetArgs window.fetch ------------------> getGetArgs
| |
navigator.credentials.get <----------------' navigator.credentials.get <----------------'
| |
'-------------------------> processGet '-------------------------> processGet
| |
alert ok or fail <----------------' alert ok or fail <----------------'
## Attestation ## Attestation
Typically, when someone logs in, you only need to confirm that they are using the same device they used during Typically, when someone logs in, you only need to confirm that they are using the same device they used during
registration. In this scenario, you do not require any form of attestation. registration. In this scenario, you do not require any form of attestation.
However, if you need additional security, such as when your company mandates the use of a Solokey for login, However, if you need additional security, such as when your company mandates the use of a Solokey for login,
you can verify its authenticity through direct attestation. Companies may also purchase authenticators that you can verify its authenticity through direct attestation. Companies may also purchase authenticators that
are signed with their own root certificate, enabling them to validate that an authenticator is affiliated with are signed with their own root certificate, enabling them to validate that an authenticator is affiliated with
their organization. their organization.
### no attestation ### no attestation
just verify that the device is the same device used on registration. just verify that the device is the same device used on registration.
You can use 'none' attestation with this library if you only check 'none' as format. You can use 'none' attestation with this library if you only check 'none' as format.
> [!TIP] > [!TIP]
> this is propably what you want to use if you want secure login for a public website. > this is propably what you want to use if you want secure login for a public website.
### indirect attestation ### indirect attestation
the browser may replace the AAGUID and attestation statement with a more privacy-friendly and/or more easily the browser may replace the AAGUID and attestation statement with a more privacy-friendly and/or more easily
verifiable version of the same data (for example, by employing an anonymization CA). verifiable version of the same data (for example, by employing an anonymization CA).
You can not validate against any root ca, if the browser uses a anonymization certificate. You can not validate against any root ca, if the browser uses a anonymization certificate.
this library sets attestation to indirect, if you select multiple formats but don't provide any root ca. this library sets attestation to indirect, if you select multiple formats but don't provide any root ca.
> [!TIP] > [!TIP]
> hybrid soultion, clients may be discouraged by browser warnings but then you know what device they're using (statistics rulez!) > hybrid soultion, clients may be discouraged by browser warnings but then you know what device they're using (statistics rulez!)
### direct attestation ### direct attestation
the browser proviedes data about the identificator device, the device can be identified uniquely. User could be tracked over multiple sites, because of that the browser may show a warning message about providing this data when register. the browser proviedes data about the identificator device, the device can be identified uniquely. User could be tracked over multiple sites, because of that the browser may show a warning message about providing this data when register.
this library sets attestation to direct, if you select multiple formats and provide root ca's. this library sets attestation to direct, if you select multiple formats and provide root ca's.
> [!TIP] > [!TIP]
> this is probably what you want if you know what devices your clients are using and make sure that only this devices are used. > this is probably what you want if you know what devices your clients are using and make sure that only this devices are used.
## Passkeys / Client-side discoverable Credentials ## Passkeys / Client-side discoverable Credentials
A Client-side discoverable Credential Source is a public key credential source whose credential private key is stored in the authenticator, A Client-side discoverable Credential Source is a public key credential source whose credential private key is stored in the authenticator,
client or client device. Such client-side storage requires a resident credential capable authenticator. client or client device. Such client-side storage requires a resident credential capable authenticator.
This is only supported by FIDO2 hardware, not by older U2F hardware. This is only supported by FIDO2 hardware, not by older U2F hardware.
>[!NOTE] >[!NOTE]
>Passkeys is a technique that allows sharing credentials stored on the device with other devices. So from a technical standpoint of the server, there is no difference to client-side discoverable credentials. The difference is only that the phone or computer system is automatically syncing the credentials between the users devices via a cloud service. The cross-device sync of passkeys is managed transparently by the OS. >Passkeys is a technique that allows sharing credentials stored on the device with other devices. So from a technical standpoint of the server, there is no difference to client-side discoverable credentials. The difference is only that the phone or computer system is automatically syncing the credentials between the users devices via a cloud service. The cross-device sync of passkeys is managed transparently by the OS.
### How does it work? ### How does it work?
In a typical server-side key management process, a user initiates a request by entering their username and, in some cases, their password. In a typical server-side key management process, a user initiates a request by entering their username and, in some cases, their password.
The server validates the user's credentials and, upon successful authentication, retrieves a list of all public key identifiers associated with that user account. The server validates the user's credentials and, upon successful authentication, retrieves a list of all public key identifiers associated with that user account.
This list is then returned to the authenticator, which selects the first credential identifier it issued and responds with a signature that can be verified using the public key registered during the registration process. This list is then returned to the authenticator, which selects the first credential identifier it issued and responds with a signature that can be verified using the public key registered during the registration process.
In a client-side key process, the user does not need to provide a username or password. In a client-side key process, the user does not need to provide a username or password.
Instead, the authenticator searches its own memory to see if it has saved a key for the relying party (domain). Instead, the authenticator searches its own memory to see if it has saved a key for the relying party (domain).
If a key is found, the authentication process proceeds in the same way as it would if the server had sent a list If a key is found, the authentication process proceeds in the same way as it would if the server had sent a list
of identifiers. There is no difference in the verification process. of identifiers. There is no difference in the verification process.
### How can I use it with this library? ### How can I use it with this library?
#### on registration #### on registration
When calling `WebAuthn\WebAuthn->getCreateArgs`, set `$requireResidentKey` to true, When calling `WebAuthn\WebAuthn->getCreateArgs`, set `$requireResidentKey` to true,
to notify the authenticator that he should save the registration in its memory. to notify the authenticator that he should save the registration in its memory.
#### on login #### on login
When calling `WebAuthn\WebAuthn->getGetArgs`, don't provide any `$credentialIds` (the authenticator will look up the ids in its own memory and returns the user ID as userHandle). When calling `WebAuthn\WebAuthn->getGetArgs`, don't provide any `$credentialIds` (the authenticator will look up the ids in its own memory and returns the user ID as userHandle).
Set the type of authenticator to `hybrid` (Passkey scanned via QR Code) and `internal` (Passkey stored on the device itself). Set the type of authenticator to `hybrid` (Passkey scanned via QR Code) and `internal` (Passkey stored on the device itself).
#### disadvantage #### disadvantage
The RP ID (= domain) is saved on the authenticator. So If an authenticator is lost, its theoretically possible to find the services, which the authenticator is used and login there. The RP ID (= domain) is saved on the authenticator. So If an authenticator is lost, its theoretically possible to find the services, which the authenticator is used and login there.
### device support ### device support
Availability of built-in passkeys that automatically synchronize to all of a users devices: (see also [passkeys.dev/device-support](https://passkeys.dev/device-support/)) Availability of built-in passkeys that automatically synchronize to all of a users devices: (see also [passkeys.dev/device-support](https://passkeys.dev/device-support/))
* Apple iOS 16+ / iPadOS 16+ / macOS Ventura+ * Apple iOS 16+ / iPadOS 16+ / macOS Ventura+
* Android 9+ * Android 9+
* Microsoft Windows 11 23H2+ * Microsoft Windows 11 23H2+
## Requirements ## Requirements
* PHP >= 8.0 with [OpenSSL](http://php.net/manual/en/book.openssl.php) and [Multibyte String](https://www.php.net/manual/en/book.mbstring.php) * PHP >= 8.0 with [OpenSSL](http://php.net/manual/en/book.openssl.php) and [Multibyte String](https://www.php.net/manual/en/book.mbstring.php)
* Browser with [WebAuthn support](https://caniuse.com/webauthn) (Firefox 60+, Chrome 67+, Edge 18+, Safari 13+) * Browser with [WebAuthn support](https://caniuse.com/webauthn) (Firefox 60+, Chrome 67+, Edge 18+, Safari 13+)
* PHP [Sodium](https://www.php.net/manual/en/book.sodium.php) (or [Sodium Compat](https://github.com/paragonie/sodium_compat) ) for [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) support * PHP [Sodium](https://www.php.net/manual/en/book.sodium.php) (or [Sodium Compat](https://github.com/paragonie/sodium_compat) ) for [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) support
## Infos about WebAuthn ## Infos about WebAuthn
* [Wikipedia](https://en.wikipedia.org/wiki/WebAuthn) * [Wikipedia](https://en.wikipedia.org/wiki/WebAuthn)
* [W3C](https://www.w3.org/TR/webauthn/) * [W3C](https://www.w3.org/TR/webauthn/)
* [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API) * [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API)
* [dev.yubico](https://developers.yubico.com/FIDO2/) * [dev.yubico](https://developers.yubico.com/FIDO2/)
* [FIDO Alliance](https://fidoalliance.org) * [FIDO Alliance](https://fidoalliance.org)
* [passkeys](https://passkeys.dev/) * [passkeys](https://passkeys.dev/)
## FIDO2 Hardware ## FIDO2 Hardware
* [Yubico](https://www.yubico.com) * [Yubico](https://www.yubico.com)
* [Solo](https://solokeys.com) Open Source! * [Solo](https://solokeys.com) Open Source!
* [Nitrokey](https://www.nitrokey.com/) * [Nitrokey](https://www.nitrokey.com/)
* [Feitan](https://fido.ftsafe.com/) * [Feitan](https://fido.ftsafe.com/)
* [TrustKey](https://www.trustkeysolutions.com) * [TrustKey](https://www.trustkeysolutions.com)
* [Google Titan](https://cloud.google.com/titan-security-key) * [Google Titan](https://cloud.google.com/titan-security-key)
* [Egis](https://www.egistec.com/u2f-solution/) * [Egis](https://www.egistec.com/u2f-solution/)
* [OneSpan](https://www.vasco.com/products/two-factor-authenticators/hardware/one-button/digipass-secureclick.html) * [OneSpan](https://www.vasco.com/products/two-factor-authenticators/hardware/one-button/digipass-secureclick.html)
* [Hypersecu](https://hypersecu.com/tmp/products/hyperfido) * [Hypersecu](https://hypersecu.com/tmp/products/hyperfido)
* [Kensington VeriMark™](https://www.kensington.com/) * [Kensington VeriMark™](https://www.kensington.com/)
* [Token2](https://www.token2.com/shop/category/fido2-keys) * [Token2](https://www.token2.com/shop/category/fido2-keys)

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +1,48 @@
Certificate: Certificate:
Data: Data:
Version: 3 (0x2) Version: 3 (0x2)
Serial Number: Serial Number:
68:1d:01:6c:7a:3c:e3:02:25:a5:01:94:28:47:57:71 68:1d:01:6c:7a:3c:e3:02:25:a5:01:94:28:47:57:71
Signature Algorithm: ecdsa-with-SHA384 Signature Algorithm: ecdsa-with-SHA384
Issuer: Issuer:
stateOrProvinceName = California stateOrProvinceName = California
organizationName = Apple Inc. organizationName = Apple Inc.
commonName = Apple WebAuthn Root CA commonName = Apple WebAuthn Root CA
Validity Validity
Not Before: Mar 18 18:21:32 2020 GMT Not Before: Mar 18 18:21:32 2020 GMT
Not After : Mar 15 00:00:00 2045 GMT Not After : Mar 15 00:00:00 2045 GMT
Subject: Subject:
stateOrProvinceName = California stateOrProvinceName = California
organizationName = Apple Inc. organizationName = Apple Inc.
commonName = Apple WebAuthn Root CA commonName = Apple WebAuthn Root CA
Subject Public Key Info: Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey Public Key Algorithm: id-ecPublicKey
ASN1 OID: secp384r1 ASN1 OID: secp384r1
X509v3 extensions: X509v3 extensions:
X509v3 Basic Constraints: critical X509v3 Basic Constraints: critical
CA:TRUE CA:TRUE
X509v3 Subject Key Identifier: X509v3 Subject Key Identifier:
26:D7:64:D9:C5:78:C2:5A:67:D1:A7:DE:6B:12:D0:1B:63:F1:C6:D7 26:D7:64:D9:C5:78:C2:5A:67:D1:A7:DE:6B:12:D0:1B:63:F1:C6:D7
X509v3 Key Usage: critical X509v3 Key Usage: critical
Certificate Sign, CRL Sign Certificate Sign, CRL Sign
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICEjCCAZmgAwIBAgIQaB0BbHo84wIlpQGUKEdXcTAKBggqhkjOPQQDAzBLMR8w MIICEjCCAZmgAwIBAgIQaB0BbHo84wIlpQGUKEdXcTAKBggqhkjOPQQDAzBLMR8w
HQYDVQQDDBZBcHBsZSBXZWJBdXRobiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ HQYDVQQDDBZBcHBsZSBXZWJBdXRobiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ
bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIwMDMxODE4MjEzMloXDTQ1MDMx bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIwMDMxODE4MjEzMloXDTQ1MDMx
NTAwMDAwMFowSzEfMB0GA1UEAwwWQXBwbGUgV2ViQXV0aG4gUm9vdCBDQTETMBEG NTAwMDAwMFowSzEfMB0GA1UEAwwWQXBwbGUgV2ViQXV0aG4gUm9vdCBDQTETMBEG
A1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTB2MBAGByqGSM49 A1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTB2MBAGByqGSM49
AgEGBSuBBAAiA2IABCJCQ2pTVhzjl4Wo6IhHtMSAzO2cv+H9DQKev3//fG59G11k AgEGBSuBBAAiA2IABCJCQ2pTVhzjl4Wo6IhHtMSAzO2cv+H9DQKev3//fG59G11k
xu9eI0/7o6V5uShBpe1u6l6mS19S1FEh6yGljnZAJ+2GNP1mi/YK2kSXIuTHjxA/ xu9eI0/7o6V5uShBpe1u6l6mS19S1FEh6yGljnZAJ+2GNP1mi/YK2kSXIuTHjxA/
pcoRf7XkOtO4o1qlcaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJtdk pcoRf7XkOtO4o1qlcaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJtdk
2cV4wlpn0afeaxLQG2PxxtcwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA 2cV4wlpn0afeaxLQG2PxxtcwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA
MGQCMFrZ+9DsJ1PW9hfNdBywZDsWDbWFp28it1d/5w2RPkRX3Bbn/UbDTNLx7Jr3 MGQCMFrZ+9DsJ1PW9hfNdBywZDsWDbWFp28it1d/5w2RPkRX3Bbn/UbDTNLx7Jr3
jAGGiQIwHFj+dJZYUJR786osByBelJYsVZd2GbHQu209b5RCmGQ21gpSAk9QZW4B jAGGiQIwHFj+dJZYUJR786osByBelJYsVZd2GbHQu209b5RCmGQ21gpSAk9QZW4B
1bWeT0vT 1bWeT0vT
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,37 +1,37 @@
Certificate: Certificate:
Data: Data:
Version: 3 (0x2) Version: 3 (0x2)
Serial Number: Serial Number:
04:00:00:00:00:01:0f:86:26:e6:0d 04:00:00:00:00:01:0f:86:26:e6:0d
Signature Algorithm: sha1WithRSAEncryption Signature Algorithm: sha1WithRSAEncryption
Issuer: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign Issuer: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
Validity Validity
Not Before: Dec 15 08:00:00 2006 GMT Not Before: Dec 15 08:00:00 2006 GMT
Not After : Dec 15 08:00:00 2021 GMT Not After : Dec 15 08:00:00 2021 GMT
Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
Subject Public Key Info: Subject Public Key Info:
Public Key Algorithm: rsaEncryption Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit) Public-Key: (2048 bit)
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs 3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS 291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,130 +1,130 @@
Google Hardware Attestation Root certificate Google Hardware Attestation Root certificate
---------------------------------------------- ----------------------------------------------
https://developer.android.com/training/articles/security-key-attestation.html https://developer.android.com/training/articles/security-key-attestation.html
Certificate: Certificate:
Data: Data:
Version: 3 (0x2) Version: 3 (0x2)
Serial Number: Serial Number:
e8:fa:19:63:14:d2:fa:18 e8:fa:19:63:14:d2:fa:18
Signature Algorithm: sha256WithRSAEncryption Signature Algorithm: sha256WithRSAEncryption
Issuer: serialNumber = f92009e853b6b045 Issuer: serialNumber = f92009e853b6b045
Validity Validity
Not Before: May 26 16:28:52 2016 GMT Not Before: May 26 16:28:52 2016 GMT
Not After : May 24 16:28:52 2026 GMT Not After : May 24 16:28:52 2026 GMT
Subject: serialNumber = f92009e853b6b045 Subject: serialNumber = f92009e853b6b045
Subject Public Key Info: Subject Public Key Info:
Public Key Algorithm: rsaEncryption Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit) Public-Key: (4096 bit)
Exponent: 65537 (0x10001) Exponent: 65537 (0x10001)
X509v3 extensions: X509v3 extensions:
X509v3 Subject Key Identifier: X509v3 Subject Key Identifier:
36:61:E1:00:7C:88:05:09:51:8B:44:6C:47:FF:1A:4C:C9:EA:4F:12 36:61:E1:00:7C:88:05:09:51:8B:44:6C:47:FF:1A:4C:C9:EA:4F:12
X509v3 Authority Key Identifier: X509v3 Authority Key Identifier:
keyid:36:61:E1:00:7C:88:05:09:51:8B:44:6C:47:FF:1A:4C:C9:EA:4F:12 keyid:36:61:E1:00:7C:88:05:09:51:8B:44:6C:47:FF:1A:4C:C9:EA:4F:12
X509v3 Basic Constraints: critical X509v3 Basic Constraints: critical
CA:TRUE CA:TRUE
X509v3 Key Usage: critical X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign Digital Signature, Certificate Sign, CRL Sign
X509v3 CRL Distribution Points: X509v3 CRL Distribution Points:
Full Name: Full Name:
URI:https://android.googleapis.com/attestation/crl/ URI:https://android.googleapis.com/attestation/crl/
Signature Algorithm: sha256WithRSAEncryption Signature Algorithm: sha256WithRSAEncryption
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIJAOj6GWMU0voYMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV MIIFYDCCA0igAwIBAgIJAOj6GWMU0voYMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV
BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTYwNTI2MTYyODUyWhcNMjYwNTI0MTYy BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTYwNTI2MTYyODUyWhcNMjYwNTI0MTYy
ODUyWjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B ODUyWjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS
Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7 Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7
tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj
nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq
C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ
oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O
JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg
sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi
igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M
RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E
aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um
AGMCAwEAAaOBpjCBozAdBgNVHQ4EFgQUNmHhAHyIBQlRi0RsR/8aTMnqTxIwHwYD AGMCAwEAAaOBpjCBozAdBgNVHQ4EFgQUNmHhAHyIBQlRi0RsR/8aTMnqTxIwHwYD
VR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwDwYDVR0TAQH/BAUwAwEB/zAO VR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwDwYDVR0TAQH/BAUwAwEB/zAO
BgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cHM6Ly9hbmRyb2lk BgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cHM6Ly9hbmRyb2lk
Lmdvb2dsZWFwaXMuY29tL2F0dGVzdGF0aW9uL2NybC8wDQYJKoZIhvcNAQELBQAD Lmdvb2dsZWFwaXMuY29tL2F0dGVzdGF0aW9uL2NybC8wDQYJKoZIhvcNAQELBQAD
ggIBACDIw41L3KlXG0aMiS//cqrG+EShHUGo8HNsw30W1kJtjn6UBwRM6jnmiwfB ggIBACDIw41L3KlXG0aMiS//cqrG+EShHUGo8HNsw30W1kJtjn6UBwRM6jnmiwfB
Pb8VA91chb2vssAtX2zbTvqBJ9+LBPGCdw/E53Rbf86qhxKaiAHOjpvAy5Y3m00m Pb8VA91chb2vssAtX2zbTvqBJ9+LBPGCdw/E53Rbf86qhxKaiAHOjpvAy5Y3m00m
qC0w/Zwvju1twb4vhLaJ5NkUJYsUS7rmJKHHBnETLi8GFqiEsqTWpG/6ibYCv7rY qC0w/Zwvju1twb4vhLaJ5NkUJYsUS7rmJKHHBnETLi8GFqiEsqTWpG/6ibYCv7rY
DBJDcR9W62BW9jfIoBQcxUCUJouMPH25lLNcDc1ssqvC2v7iUgI9LeoM1sNovqPm DBJDcR9W62BW9jfIoBQcxUCUJouMPH25lLNcDc1ssqvC2v7iUgI9LeoM1sNovqPm
QUiG9rHli1vXxzCyaMTjwftkJLkf6724DFhuKug2jITV0QkXvaJWF4nUaHOTNA4u QUiG9rHli1vXxzCyaMTjwftkJLkf6724DFhuKug2jITV0QkXvaJWF4nUaHOTNA4u
JU9WDvZLI1j83A+/xnAJUucIv/zGJ1AMH2boHqF8CY16LpsYgBt6tKxxWH00XcyD JU9WDvZLI1j83A+/xnAJUucIv/zGJ1AMH2boHqF8CY16LpsYgBt6tKxxWH00XcyD
CdW2KlBCeqbQPcsFmWyWugxdcekhYsAWyoSf818NUsZdBWBaR/OukXrNLfkQ79Iy CdW2KlBCeqbQPcsFmWyWugxdcekhYsAWyoSf818NUsZdBWBaR/OukXrNLfkQ79Iy
ZohZbvabO/X+MVT3rriAoKc8oE2Uws6DF+60PV7/WIPjNvXySdqspImSN78mflxD ZohZbvabO/X+MVT3rriAoKc8oE2Uws6DF+60PV7/WIPjNvXySdqspImSN78mflxD
qwLqRBYkA3I75qppLGG9rp7UCdRjxMl8ZDBld+7yvHVgt1cVzJx9xnyGCC23Uaic qwLqRBYkA3I75qppLGG9rp7UCdRjxMl8ZDBld+7yvHVgt1cVzJx9xnyGCC23Uaic
MDSXYrB4I4WHXPGjxhZuCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1 MDSXYrB4I4WHXPGjxhZuCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1
wDB5y0USicV3YgYGmi+NZfhA4URSh77Yd6uuJOJENRaNVTzk wDB5y0USicV3YgYGmi+NZfhA4URSh77Yd6uuJOJENRaNVTzk
-----END CERTIFICATE----- -----END CERTIFICATE-----
Certificate: Certificate:
Data: Data:
Version: 3 (0x2) Version: 3 (0x2)
Serial Number: 15352756130135856819 (0xd50ff25ba3f2d6b3) Serial Number: 15352756130135856819 (0xd50ff25ba3f2d6b3)
Signature Algorithm: sha256WithRSAEncryption Signature Algorithm: sha256WithRSAEncryption
Issuer: Issuer:
serialNumber = f92009e853b6b045 serialNumber = f92009e853b6b045
Validity Validity
Not Before: Nov 22 20:37:58 2019 GMT Not Before: Nov 22 20:37:58 2019 GMT
Not After : Nov 18 20:37:58 2034 GMT Not After : Nov 18 20:37:58 2034 GMT
Subject: Subject:
serialNumber = f92009e853b6b045 serialNumber = f92009e853b6b045
Subject Public Key Info: Subject Public Key Info:
Public Key Algorithm: rsaEncryption Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit) Public-Key: (4096 bit)
Exponent: 65537 (0x10001) Exponent: 65537 (0x10001)
X509v3 extensions: X509v3 extensions:
X509v3 Subject Key Identifier: X509v3 Subject Key Identifier:
36:61:E1:00:7C:88:05:09:51:8B:44:6C:47:FF:1A:4C:C9:EA:4F:12 36:61:E1:00:7C:88:05:09:51:8B:44:6C:47:FF:1A:4C:C9:EA:4F:12
X509v3 Authority Key Identifier: X509v3 Authority Key Identifier:
keyid:36:61:E1:00:7C:88:05:09:51:8B:44:6C:47:FF:1A:4C:C9:EA:4F:12 keyid:36:61:E1:00:7C:88:05:09:51:8B:44:6C:47:FF:1A:4C:C9:EA:4F:12
X509v3 Basic Constraints: critical X509v3 Basic Constraints: critical
CA:TRUE CA:TRUE
X509v3 Key Usage: critical X509v3 Key Usage: critical
Certificate Sign Certificate Sign
Signature Algorithm: sha256WithRSAEncryption Signature Algorithm: sha256WithRSAEncryption
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIFHDCCAwSgAwIBAgIJANUP8luj8tazMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV MIIFHDCCAwSgAwIBAgIJANUP8luj8tazMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV
BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTkxMTIyMjAzNzU4WhcNMzQxMTE4MjAz BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTkxMTIyMjAzNzU4WhcNMzQxMTE4MjAz
NzU4WjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B NzU4WjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS
Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7 Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7
tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj
nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq
C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ
oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O
JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg
sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi
igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M
RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E
aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um
AGMCAwEAAaNjMGEwHQYDVR0OBBYEFDZh4QB8iAUJUYtEbEf/GkzJ6k8SMB8GA1Ud AGMCAwEAAaNjMGEwHQYDVR0OBBYEFDZh4QB8iAUJUYtEbEf/GkzJ6k8SMB8GA1Ud
IwQYMBaAFDZh4QB8iAUJUYtEbEf/GkzJ6k8SMA8GA1UdEwEB/wQFMAMBAf8wDgYD IwQYMBaAFDZh4QB8iAUJUYtEbEf/GkzJ6k8SMA8GA1UdEwEB/wQFMAMBAf8wDgYD
VR0PAQH/BAQDAgIEMA0GCSqGSIb3DQEBCwUAA4ICAQBOMaBc8oumXb2voc7XCWnu VR0PAQH/BAQDAgIEMA0GCSqGSIb3DQEBCwUAA4ICAQBOMaBc8oumXb2voc7XCWnu
XKhBBK3e2KMGz39t7lA3XXRe2ZLLAkLM5y3J7tURkf5a1SutfdOyXAmeE6SRo83U XKhBBK3e2KMGz39t7lA3XXRe2ZLLAkLM5y3J7tURkf5a1SutfdOyXAmeE6SRo83U
h6WszodmMkxK5GM4JGrnt4pBisu5igXEydaW7qq2CdC6DOGjG+mEkN8/TA6p3cno h6WszodmMkxK5GM4JGrnt4pBisu5igXEydaW7qq2CdC6DOGjG+mEkN8/TA6p3cno
L/sPyz6evdjLlSeJ8rFBH6xWyIZCbrcpYEJzXaUOEaxxXxgYz5/cTiVKN2M1G2ok L/sPyz6evdjLlSeJ8rFBH6xWyIZCbrcpYEJzXaUOEaxxXxgYz5/cTiVKN2M1G2ok
QBUIYSY6bjEL4aUN5cfo7ogP3UvliEo3Eo0YgwuzR2v0KR6C1cZqZJSTnghIC/vA QBUIYSY6bjEL4aUN5cfo7ogP3UvliEo3Eo0YgwuzR2v0KR6C1cZqZJSTnghIC/vA
D32KdNQ+c3N+vl2OTsUVMC1GiWkngNx1OO1+kXW+YTnnTUOtOIswUP/Vqd5SYgAI D32KdNQ+c3N+vl2OTsUVMC1GiWkngNx1OO1+kXW+YTnnTUOtOIswUP/Vqd5SYgAI
mMAfY8U9/iIgkQj6T2W6FsScy94IN9fFhE1UtzmLoBIuUFsVXJMTz+Jucth+IqoW mMAfY8U9/iIgkQj6T2W6FsScy94IN9fFhE1UtzmLoBIuUFsVXJMTz+Jucth+IqoW
Fua9v1R93/k98p41pjtFX+H8DslVgfP097vju4KDlqN64xV1grw3ZLl4CiOe/A91 Fua9v1R93/k98p41pjtFX+H8DslVgfP097vju4KDlqN64xV1grw3ZLl4CiOe/A91
oeLm2UHOq6wn3esB4r2EIQKb6jTVGu5sYCcdWpXr0AUVqcABPdgL+H7qJguBw09o oeLm2UHOq6wn3esB4r2EIQKb6jTVGu5sYCcdWpXr0AUVqcABPdgL+H7qJguBw09o
jm6xNIrw2OocrDKsudk/okr/AwqEyPKw9WnMlQgLIKw1rODG2NvU9oR3GVGdMkUB jm6xNIrw2OocrDKsudk/okr/AwqEyPKw9WnMlQgLIKw1rODG2NvU9oR3GVGdMkUB
ZutL8VuFkERQGt6vQ2OCw0sV47VMkuYbacK/xyZFiRcrPJPb41zgbQj9XAEyLKCH ZutL8VuFkERQGt6vQ2OCw0sV47VMkuYbacK/xyZFiRcrPJPb41zgbQj9XAEyLKCH
ex0SdDrx+tWUDqG8At2JHA== ex0SdDrx+tWUDqG8At2JHA==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,56 +1,56 @@
HyperFIDO U2F Security Key Attestation CA HyperFIDO U2F Security Key Attestation CA
https://hypersecu.com/support/downloads/attestation https://hypersecu.com/support/downloads/attestation
Last Update: 2017-01-01 Last Update: 2017-01-01
HyperFIDO U2F Security Key devices which contain attestation certificates signed by a set of CAs. HyperFIDO U2F Security Key devices which contain attestation certificates signed by a set of CAs.
This file contains the CA certificates that Relying Parties (RP) need to configure their software This file contains the CA certificates that Relying Parties (RP) need to configure their software
with to be able to verify U2F device certificates. with to be able to verify U2F device certificates.
The file will be updated as needed when we publish more CA certificates. The file will be updated as needed when we publish more CA certificates.
Issuer: CN=FT FIDO 0100 Issuer: CN=FT FIDO 0100
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIBjTCCATOgAwIBAgIBATAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxGVCBGSURP MIIBjTCCATOgAwIBAgIBATAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxGVCBGSURP
IDAxMDAwHhcNMTQwNzAxMTUzNjI2WhcNNDQwNzAzMTUzNjI2WjAXMRUwEwYDVQQD IDAxMDAwHhcNMTQwNzAxMTUzNjI2WhcNNDQwNzAzMTUzNjI2WjAXMRUwEwYDVQQD
EwxGVCBGSURPIDAxMDAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASxdLxJx8ol EwxGVCBGSURPIDAxMDAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASxdLxJx8ol
S3DS5cIHzunPF0gg69d+o8ZVCMJtpRtlfBzGuVL4YhaXk2SC2gptPTgmpZCV2vbN S3DS5cIHzunPF0gg69d+o8ZVCMJtpRtlfBzGuVL4YhaXk2SC2gptPTgmpZCV2vbN
fAPi5gOF0vbZo3AwbjAdBgNVHQ4EFgQUXt4jWlYDgwhaPU+EqLmeM9LoPRMwPwYD fAPi5gOF0vbZo3AwbjAdBgNVHQ4EFgQUXt4jWlYDgwhaPU+EqLmeM9LoPRMwPwYD
VR0jBDgwNoAUXt4jWlYDgwhaPU+EqLmeM9LoPROhG6QZMBcxFTATBgNVBAMTDEZU VR0jBDgwNoAUXt4jWlYDgwhaPU+EqLmeM9LoPROhG6QZMBcxFTATBgNVBAMTDEZU
IEZJRE8gMDEwMIIBATAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQC2 IEZJRE8gMDEwMIIBATAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQC2
D9o9cconKTo8+4GZPyZBJ3amc8F0/kzyidX9dhrAIAIgM9ocs5BW/JfmshVP9Mb+ D9o9cconKTo8+4GZPyZBJ3amc8F0/kzyidX9dhrAIAIgM9ocs5BW/JfmshVP9Mb+
Joa/kgX4dWbZxrk0ioTfJZg= Joa/kgX4dWbZxrk0ioTfJZg=
-----END CERTIFICATE----- -----END CERTIFICATE-----
Certificate: Certificate:
Data: Data:
Version: 3 (0x2) Version: 3 (0x2)
Serial Number: 4107 (0x100b) Serial Number: 4107 (0x100b)
Signature Algorithm: ecdsa-with-SHA256 Signature Algorithm: ecdsa-with-SHA256
Issuer: Issuer:
commonName = HYPERFIDO 0200 commonName = HYPERFIDO 0200
organizationName = HYPERSECU organizationName = HYPERSECU
countryName = CA countryName = CA
Validity Validity
Not Before: Jan 1 00:00:00 2018 GMT Not Before: Jan 1 00:00:00 2018 GMT
Not After : Dec 31 23:59:59 2047 GMT Not After : Dec 31 23:59:59 2047 GMT
Subject: Subject:
commonName = HYPERFIDO 0200 commonName = HYPERFIDO 0200
organizationName = HYPERSECU organizationName = HYPERSECU
countryName = CA countryName = CA
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIBxzCCAWygAwIBAgICEAswCgYIKoZIzj0EAwIwOjELMAkGA1UEBhMCQ0ExEjAQ MIIBxzCCAWygAwIBAgICEAswCgYIKoZIzj0EAwIwOjELMAkGA1UEBhMCQ0ExEjAQ
BgNVBAoMCUhZUEVSU0VDVTEXMBUGA1UEAwwOSFlQRVJGSURPIDAyMDAwIBcNMTgw BgNVBAoMCUhZUEVSU0VDVTEXMBUGA1UEAwwOSFlQRVJGSURPIDAyMDAwIBcNMTgw
MTAxMDAwMDAwWhgPMjA0NzEyMzEyMzU5NTlaMDoxCzAJBgNVBAYTAkNBMRIwEAYD MTAxMDAwMDAwWhgPMjA0NzEyMzEyMzU5NTlaMDoxCzAJBgNVBAYTAkNBMRIwEAYD
VQQKDAlIWVBFUlNFQ1UxFzAVBgNVBAMMDkhZUEVSRklETyAwMjAwMFkwEwYHKoZI VQQKDAlIWVBFUlNFQ1UxFzAVBgNVBAMMDkhZUEVSRklETyAwMjAwMFkwEwYHKoZI
zj0CAQYIKoZIzj0DAQcDQgAErKUI1G0S7a6IOLlmHipLlBuxTYjsEESQvzQh3dB7 zj0CAQYIKoZIzj0DAQcDQgAErKUI1G0S7a6IOLlmHipLlBuxTYjsEESQvzQh3dB7
dvxxWWm7kWL91rq6S7ayZG0gZPR+zYqdFzwAYDcG4+aX66NgMF4wHQYDVR0OBBYE dvxxWWm7kWL91rq6S7ayZG0gZPR+zYqdFzwAYDcG4+aX66NgMF4wHQYDVR0OBBYE
FLZYcfMMwkQAGbt3ryzZFPFypmsIMB8GA1UdIwQYMBaAFLZYcfMMwkQAGbt3ryzZ FLZYcfMMwkQAGbt3ryzZFPFypmsIMB8GA1UdIwQYMBaAFLZYcfMMwkQAGbt3ryzZ
FPFypmsIMAwGA1UdEwQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMC FPFypmsIMAwGA1UdEwQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMC
A0kAMEYCIQCG2/ppMGt7pkcRie5YIohS3uDPIrmiRcTjqDclKVWg0gIhANcPNDZH A0kAMEYCIQCG2/ppMGt7pkcRie5YIohS3uDPIrmiRcTjqDclKVWg0gIhANcPNDZH
E2/zZ+uB5ThG9OZus+xSb4knkrbAyXKX2zm/ E2/zZ+uB5ThG9OZus+xSb4knkrbAyXKX2zm/
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,41 +1,41 @@
Solokeys FIDO2/U2F Device Attestation CA Solokeys FIDO2/U2F Device Attestation CA
======================================== ========================================
Data: Data:
Version: 1 (0x0) Version: 1 (0x0)
Serial Number: 14143382635911888524 (0xc44763928ff4be8c) Serial Number: 14143382635911888524 (0xc44763928ff4be8c)
Signature Algorithm: ecdsa-with-SHA256 Signature Algorithm: ecdsa-with-SHA256
Issuer: Issuer:
emailAddress = hello@solokeys.com emailAddress = hello@solokeys.com
commonName = solokeys.com commonName = solokeys.com
organizationalUnitName = Root CA organizationalUnitName = Root CA
organizationName = Solo Keys organizationName = Solo Keys
stateOrProvinceName = Maryland stateOrProvinceName = Maryland
countryName = US countryName = US
Validity Validity
Not Before: Nov 11 12:51:42 2018 GMT Not Before: Nov 11 12:51:42 2018 GMT
Not After : Oct 29 12:51:42 2068 GMT Not After : Oct 29 12:51:42 2068 GMT
Subject: Subject:
emailAddress = hello@solokeys.com emailAddress = hello@solokeys.com
commonName = solokeys.com commonName = solokeys.com
organizationalUnitName = Root CA organizationalUnitName = Root CA
organizationName = Solo Keys organizationName = Solo Keys
stateOrProvinceName = Maryland stateOrProvinceName = Maryland
countryName = US countryName = US
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIB9DCCAZoCCQDER2OSj/S+jDAKBggqhkjOPQQDAjCBgDELMAkGA1UEBhMCVVMx MIIB9DCCAZoCCQDER2OSj/S+jDAKBggqhkjOPQQDAjCBgDELMAkGA1UEBhMCVVMx
ETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQKDAlTb2xvIEtleXMxEDAOBgNVBAsM ETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQKDAlTb2xvIEtleXMxEDAOBgNVBAsM
B1Jvb3QgQ0ExFTATBgNVBAMMDHNvbG9rZXlzLmNvbTEhMB8GCSqGSIb3DQEJARYS B1Jvb3QgQ0ExFTATBgNVBAMMDHNvbG9rZXlzLmNvbTEhMB8GCSqGSIb3DQEJARYS
aGVsbG9Ac29sb2tleXMuY29tMCAXDTE4MTExMTEyNTE0MloYDzIwNjgxMDI5MTI1 aGVsbG9Ac29sb2tleXMuY29tMCAXDTE4MTExMTEyNTE0MloYDzIwNjgxMDI5MTI1
MTQyWjCBgDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQK MTQyWjCBgDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQK
DAlTb2xvIEtleXMxEDAOBgNVBAsMB1Jvb3QgQ0ExFTATBgNVBAMMDHNvbG9rZXlz DAlTb2xvIEtleXMxEDAOBgNVBAsMB1Jvb3QgQ0ExFTATBgNVBAMMDHNvbG9rZXlz
LmNvbTEhMB8GCSqGSIb3DQEJARYSaGVsbG9Ac29sb2tleXMuY29tMFkwEwYHKoZI LmNvbTEhMB8GCSqGSIb3DQEJARYSaGVsbG9Ac29sb2tleXMuY29tMFkwEwYHKoZI
zj0CAQYIKoZIzj0DAQcDQgAEWHAN0CCJVZdMs0oktZ5m93uxmB1iyq8ELRLtqVFL zj0CAQYIKoZIzj0DAQcDQgAEWHAN0CCJVZdMs0oktZ5m93uxmB1iyq8ELRLtqVFL
SOiHQEab56qRTB/QzrpGAY++Y2mw+vRuQMNhBiU0KzwjBjAKBggqhkjOPQQDAgNI SOiHQEab56qRTB/QzrpGAY++Y2mw+vRuQMNhBiU0KzwjBjAKBggqhkjOPQQDAgNI
ADBFAiEAz9SlrAXIlEu87vra54rICPs+4b0qhp3PdzcTg7rvnP0CIGjxzlteQQx+ ADBFAiEAz9SlrAXIlEu87vra54rICPs+4b0qhp3PdzcTg7rvnP0CIGjxzlteQQx+
jQGd7rwSZuE5RWUPVygYhUstQO9zNUOs jQGd7rwSZuE5RWUPVygYhUstQO9zNUOs
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,23 +1,23 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIID6TCCAdGgAwIBAgIUUAjLh3ownidqbj5fboDmufVXiecwDQYJKoZIhvcNAQEL MIID6TCCAdGgAwIBAgIUUAjLh3ownidqbj5fboDmufVXiecwDQYJKoZIhvcNAQEL
BQAwMjERMA8GA1UECgwIU29sb0tleXMxCzAJBgNVBAYTAkNIMRAwDgYDVQQDDAdS BQAwMjERMA8GA1UECgwIU29sb0tleXMxCzAJBgNVBAYTAkNIMRAwDgYDVQQDDAdS
b290IFIxMCAXDTIxMDUyODA4MjQxMloYDzIwNzEwNTE2MDgyNDEyWjAtMREwDwYD b290IFIxMCAXDTIxMDUyODA4MjQxMloYDzIwNzEwNTE2MDgyNDEyWjAtMREwDwYD
VQQKDAhTb2xvS2V5czELMAkGA1UEBhMCQ0gxCzAJBgNVBAMMAkYxMFkwEwYHKoZI VQQKDAhTb2xvS2V5czELMAkGA1UEBhMCQ0gxCzAJBgNVBAMMAkYxMFkwEwYHKoZI
zj0CAQYIKoZIzj0DAQcDQgAEPCcSladE9kbZ0XI7jmtceNSHVrC1Rx0d3U8aMvKS zj0CAQYIKoZIzj0DAQcDQgAEPCcSladE9kbZ0XI7jmtceNSHVrC1Rx0d3U8aMvKS
CJimYSe7c0Jy7CZpw7TU6N6chNx6Q1jaZ/B3ZjPLGZBOMqOBxDCBwTAdBgNVHQ4E CJimYSe7c0Jy7CZpw7TU6N6chNx6Q1jaZ/B3ZjPLGZBOMqOBxDCBwTAdBgNVHQ4E
FgQUQWu2S++iGQ3kYl/9KQSWuYIptPgwHwYDVR0jBBgwFoAUVOPVaecSkRBulbOE FgQUQWu2S++iGQ3kYl/9KQSWuYIptPgwHwYDVR0jBBgwFoAUVOPVaecSkRBulbOE
QMfZOr8x1dcwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwMgYI QMfZOr8x1dcwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwMgYI
KwYBBQUHAQEEJjAkMCIGCCsGAQUFBzAChhZodHRwOi8vaS5zMnBraS5uZXQvcjEv KwYBBQUHAQEEJjAkMCIGCCsGAQUFBzAChhZodHRwOi8vaS5zMnBraS5uZXQvcjEv
MCcGA1UdHwQgMB4wHKAaoBiGFmh0dHA6Ly9jLnMycGtpLm5ldC9yMS8wDQYJKoZI MCcGA1UdHwQgMB4wHKAaoBiGFmh0dHA6Ly9jLnMycGtpLm5ldC9yMS8wDQYJKoZI
hvcNAQELBQADggIBACVIymBmQwWwIUKnffptCJPeAn4m+Vy7ntr6KeS6aM7NI3cb hvcNAQELBQADggIBACVIymBmQwWwIUKnffptCJPeAn4m+Vy7ntr6KeS6aM7NI3cb
xzRq5tHOugtjFJsBSGynbF0/Kc+VnGR2lCFuVKeuusFsAhk4F13jaOTPSTWTXK6k xzRq5tHOugtjFJsBSGynbF0/Kc+VnGR2lCFuVKeuusFsAhk4F13jaOTPSTWTXK6k
2TdoqZ6wIqmQ7bAZVYqcE21ZkM/Bo5Ej+PZacGjlGaEHwjL5CU2scnZeqS8d1ago 2TdoqZ6wIqmQ7bAZVYqcE21ZkM/Bo5Ej+PZacGjlGaEHwjL5CU2scnZeqS8d1ago
MCIfvRlYd2vkbPjqQx0t5jzEKZ7hF4y77kh0JArYpgpp0Sq4P96pPDwIZCvVGmGi MCIfvRlYd2vkbPjqQx0t5jzEKZ7hF4y77kh0JArYpgpp0Sq4P96pPDwIZCvVGmGi
jhNOie0UnF6trfTD1AAXtlPqYPK9gNpXlN2IhsIpNMf7YA9R1zjVvnfYnFS6Tr73 jhNOie0UnF6trfTD1AAXtlPqYPK9gNpXlN2IhsIpNMf7YA9R1zjVvnfYnFS6Tr73
0UzBct6jC9JompqvAo9NIe6cu/Qkc/KUL4JDt9iJWB8RN2aAnVCYQ+xT4evVFQCV 0UzBct6jC9JompqvAo9NIe6cu/Qkc/KUL4JDt9iJWB8RN2aAnVCYQ+xT4evVFQCV
F/1pbeSvFfPqCfazkSPIiff7n9Tmk1Wwe3VmkuU7HUmAkYaLazs7DLY/Cp0/1V1K F/1pbeSvFfPqCfazkSPIiff7n9Tmk1Wwe3VmkuU7HUmAkYaLazs7DLY/Cp0/1V1K
pURMyawlUtv2J4PQqvOnMGUYupxp2l3DjdzHMx8RE+caCM2PxzPsUucLVHdOkBW2 pURMyawlUtv2J4PQqvOnMGUYupxp2l3DjdzHMx8RE+caCM2PxzPsUucLVHdOkBW2
h6U5PIWJuZtbiabwFmQXahqSNkRO6kXRvedowqaHNZiIFi4VKqPHrJrEhNhncfJ/ h6U5PIWJuZtbiabwFmQXahqSNkRO6kXRvedowqaHNZiIFi4VKqPHrJrEhNhncfJ/
jwAAThoo5yyEgh3a+THoZKOFfZhzFJA9MVMwqQB00iSsF5HKC+MFUkHpKaV2DVjS jwAAThoo5yyEgh3a+THoZKOFfZhzFJA9MVMwqQB00iSsF5HKC+MFUkHpKaV2DVjS
mPXOYy4biL8XkOqQeJUuB5sQ/2LYxaaXj1dBrnR3cklHp2KKacWYdnLdEe8I mPXOYy4biL8XkOqQeJUuB5sQ/2LYxaaXj1dBrnR3cklHp2KKacWYdnLdEe8I
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,31 +1,31 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIFVzCCAz+gAwIBAgIUR9xt5vBCCwFTaFGS3VFH0v49lmUwDQYJKoZIhvcNAQEL MIIFVzCCAz+gAwIBAgIUR9xt5vBCCwFTaFGS3VFH0v49lmUwDQYJKoZIhvcNAQEL
BQAwMjERMA8GA1UECgwIU29sb0tleXMxCzAJBgNVBAYTAkNIMRAwDgYDVQQDDAdS BQAwMjERMA8GA1UECgwIU29sb0tleXMxCzAJBgNVBAYTAkNIMRAwDgYDVQQDDAdS
b290IFIxMCAXDTIxMDUyMTIyMTA1M1oYDzIwNzEwNTA5MjIxMDUzWjAyMREwDwYD b290IFIxMCAXDTIxMDUyMTIyMTA1M1oYDzIwNzEwNTA5MjIxMDUzWjAyMREwDwYD
VQQKDAhTb2xvS2V5czELMAkGA1UEBhMCQ0gxEDAOBgNVBAMMB1Jvb3QgUjEwggIi VQQKDAhTb2xvS2V5czELMAkGA1UEBhMCQ0gxEDAOBgNVBAMMB1Jvb3QgUjEwggIi
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCBybLOEMbhPyBEaHeqXJQUfRgd MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCBybLOEMbhPyBEaHeqXJQUfRgd
xZHFtum2oXknCineXh8NXBL8PJLJEYi4Clv/QQGj+VPGPOcF1nwMX5BsmTYsLPMo xZHFtum2oXknCineXh8NXBL8PJLJEYi4Clv/QQGj+VPGPOcF1nwMX5BsmTYsLPMo
Rt7npI/xaPYdW/ByIvQQNqH3NTQjt8j4Wz0XWHL/VuqNFGZAdI4GN00NifKH1FCy Rt7npI/xaPYdW/ByIvQQNqH3NTQjt8j4Wz0XWHL/VuqNFGZAdI4GN00NifKH1FCy
wOgwyKHl74XmMJLzzigFoo8m5ZPD+uw7ZRt1Q28jFTJiB2qyMX1rn2wHZLnHHhgs wOgwyKHl74XmMJLzzigFoo8m5ZPD+uw7ZRt1Q28jFTJiB2qyMX1rn2wHZLnHHhgs
wp0uApnQw5CGmhK3pkW8U9Gr3JH6K0q6NwZ4Pp1DPJFbl4J9cPFP2o25sOsf+jjX wp0uApnQw5CGmhK3pkW8U9Gr3JH6K0q6NwZ4Pp1DPJFbl4J9cPFP2o25sOsf+jjX
4Ko2J97qndoRxHFWjh6HLvbq6/RyySbVGBsBeep92QXidf/3Vgc+6xkgTmlWL+5W 4Ko2J97qndoRxHFWjh6HLvbq6/RyySbVGBsBeep92QXidf/3Vgc+6xkgTmlWL+5W
6mj7F8zhPAz8l8m3HEv/pVdsJikwrR2FAllw4T2nBYXhdJ4lPdH9HYZrbmyGVOcD 6mj7F8zhPAz8l8m3HEv/pVdsJikwrR2FAllw4T2nBYXhdJ4lPdH9HYZrbmyGVOcD
1M/hQ2d/7X0H1K40KV1li1nYJHxkfcDKHeI5RcAaLE+n6ctLS5KqyJ0MXmmga6I7 1M/hQ2d/7X0H1K40KV1li1nYJHxkfcDKHeI5RcAaLE+n6ctLS5KqyJ0MXmmga6I7
rd5cTfQqjYQm/YbfShK6ZsmsGC/KJGmFbx9kqsMbcg7a2qF1RT0WPFJd2F1glaon rd5cTfQqjYQm/YbfShK6ZsmsGC/KJGmFbx9kqsMbcg7a2qF1RT0WPFJd2F1glaon
tsqPwFDi5mR7M46tjLAWJx2Wu5mbACedRoxKPMe8l+b1CQ7k+temvxNK0IvM38St tsqPwFDi5mR7M46tjLAWJx2Wu5mbACedRoxKPMe8l+b1CQ7k+temvxNK0IvM38St
z9UiVpl0VwACNpJ2MobM+XJNQNCbMbBt0n6wPmftqI5taoFxPTNM6t1F2utsjbdn z9UiVpl0VwACNpJ2MobM+XJNQNCbMbBt0n6wPmftqI5taoFxPTNM6t1F2utsjbdn
M1/WUKOh5lhheBMDWQIDAQABo2MwYTAdBgNVHQ4EFgQUVOPVaecSkRBulbOEQMfZ M1/WUKOh5lhheBMDWQIDAQABo2MwYTAdBgNVHQ4EFgQUVOPVaecSkRBulbOEQMfZ
Or8x1dcwHwYDVR0jBBgwFoAUVOPVaecSkRBulbOEQMfZOr8x1dcwDwYDVR0TAQH/ Or8x1dcwHwYDVR0jBBgwFoAUVOPVaecSkRBulbOEQMfZOr8x1dcwDwYDVR0TAQH/
BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAEh5VMjC BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAEh5VMjC
YnWzJK8Rolmsbmpa7LQiS+WKk2ihYZRLUYlzET5+MDmue+n4sBuuuXPLaQsdnTSO YnWzJK8Rolmsbmpa7LQiS+WKk2ihYZRLUYlzET5+MDmue+n4sBuuuXPLaQsdnTSO
xqmVts8bneacEckr0y8j5/2o5/5UPjAchXXK6PwHqnajk2kzCIH2tWTyhpKcxF1i xqmVts8bneacEckr0y8j5/2o5/5UPjAchXXK6PwHqnajk2kzCIH2tWTyhpKcxF1i
fQo9RGA6igOjes8vMmKCFQg3A88wiAtrafgf/I3fVSHJOSeU29nqmVNHGU4tQFu0 fQo9RGA6igOjes8vMmKCFQg3A88wiAtrafgf/I3fVSHJOSeU29nqmVNHGU4tQFu0
Frx/d3y5elo5rZpld71DwRA83qLUgJ3liancoSb/icR8igGyLxCcxmKU5fFItiG9 Frx/d3y5elo5rZpld71DwRA83qLUgJ3liancoSb/icR8igGyLxCcxmKU5fFItiG9
4x+egnblyYfuhLbXU0k8LXJVMdDImZHEyI80EHOSpV3wZR5LyfiXu3fygxtOm6tL 4x+egnblyYfuhLbXU0k8LXJVMdDImZHEyI80EHOSpV3wZR5LyfiXu3fygxtOm6tL
fi1khkJIfIPMyV1Y4B7y6zOlHbneF1F8P4pTjHTYFHKhNm1wWffrqgLDYdtLAXSV fi1khkJIfIPMyV1Y4B7y6zOlHbneF1F8P4pTjHTYFHKhNm1wWffrqgLDYdtLAXSV
tyDM0zjtoRSHRYWsuwbeWdwoWHQeLkPzMtmFkHrPi0i3iv4GaianTnE1k1lX8Xf4 tyDM0zjtoRSHRYWsuwbeWdwoWHQeLkPzMtmFkHrPi0i3iv4GaianTnE1k1lX8Xf4
HbWBHXoVJCoAwycJJqX2SPZwFlWGp8IMGLUNzjFtLP+D7pdUSBgkDqz6FumZQGx/ HbWBHXoVJCoAwycJJqX2SPZwFlWGp8IMGLUNzjFtLP+D7pdUSBgkDqz6FumZQGx/
KLHugnolEb8ZiOZKbaPOjc9EmXFjA42y4vXAip6ZZ2FfuWDqkPaU1WfM95cE0hf5 KLHugnolEb8ZiOZKbaPOjc9EmXFjA42y4vXAip6ZZ2FfuWDqkPaU1WfM95cE0hf5
BSbfxSSQ2V3z4sywzkfQxr7q2mYzJ9C2NhLYXMrc98L9uEd0O7dO0eEF+44gc5O7 BSbfxSSQ2V3z4sywzkfQxr7q2mYzJ9C2NhLYXMrc98L9uEd0O7dO0eEF+44gc5O7
Bc7NuTA9//IG8nJb0MvD76TxHPlZuVnMdMb6 Bc7NuTA9//IG8nJb0MvD76TxHPlZuVnMdMb6
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,42 +1,42 @@
Yubico U2F Device Attestation CA Yubico U2F Device Attestation CA
================================ ================================
Last Update: 2014-09-01 Last Update: 2014-09-01
Yubico manufacturer U2F devices that contains device attestation Yubico manufacturer U2F devices that contains device attestation
certificates signed by a set of Yubico CAs. This file contains the CA certificates signed by a set of Yubico CAs. This file contains the CA
certificates that Relying Parties (RP) need to configure their certificates that Relying Parties (RP) need to configure their
software with to be able to verify U2F device certificates. software with to be able to verify U2F device certificates.
This file has been signed with OpenPGP and you should verify the This file has been signed with OpenPGP and you should verify the
signature and the authenticity of the public key before trusting the signature and the authenticity of the public key before trusting the
content. The signature is located next to the file: content. The signature is located next to the file:
https://developers.yubico.com/u2f/yubico-u2f-ca-certs.txt https://developers.yubico.com/u2f/yubico-u2f-ca-certs.txt
https://developers.yubico.com/u2f/yubico-u2f-ca-certs.txt.sig https://developers.yubico.com/u2f/yubico-u2f-ca-certs.txt.sig
We will update this file from time to time when we publish more CA We will update this file from time to time when we publish more CA
certificates. certificates.
Name: Yubico U2F Root CA Serial 457200631 Name: Yubico U2F Root CA Serial 457200631
Issued: 2014-08-01 Issued: 2014-08-01
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDHjCCAgagAwIBAgIEG0BT9zANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZ MIIDHjCCAgagAwIBAgIEG0BT9zANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZ
dWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAw dWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAw
MDBaGA8yMDUwMDkwNDAwMDAwMFowLjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290 MDBaGA8yMDUwMDkwNDAwMDAwMFowLjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290
IENBIFNlcmlhbCA0NTcyMDA2MzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK IENBIFNlcmlhbCA0NTcyMDA2MzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC/jwYuhBVlqaiYWEMsrWFisgJ+PtM91eSrpI4TK7U53mwCIawSDHy8vUmk AoIBAQC/jwYuhBVlqaiYWEMsrWFisgJ+PtM91eSrpI4TK7U53mwCIawSDHy8vUmk
5N2KAj9abvT9NP5SMS1hQi3usxoYGonXQgfO6ZXyUA9a+KAkqdFnBnlyugSeCOep 5N2KAj9abvT9NP5SMS1hQi3usxoYGonXQgfO6ZXyUA9a+KAkqdFnBnlyugSeCOep
8EdZFfsaRFtMjkwz5Gcz2Py4vIYvCdMHPtwaz0bVuzneueIEz6TnQjE63Rdt2zbw 8EdZFfsaRFtMjkwz5Gcz2Py4vIYvCdMHPtwaz0bVuzneueIEz6TnQjE63Rdt2zbw
nebwTG5ZybeWSwbzy+BJ34ZHcUhPAY89yJQXuE0IzMZFcEBbPNRbWECRKgjq//qT nebwTG5ZybeWSwbzy+BJ34ZHcUhPAY89yJQXuE0IzMZFcEBbPNRbWECRKgjq//qT
9nmDOFVlSRCt2wiqPSzluwn+v+suQEBsUjTGMEd25tKXXTkNW21wIWbxeSyUoTXw 9nmDOFVlSRCt2wiqPSzluwn+v+suQEBsUjTGMEd25tKXXTkNW21wIWbxeSyUoTXw
LvGS6xlwQSgNpk2qXYwf8iXg7VWZAgMBAAGjQjBAMB0GA1UdDgQWBBQgIvz0bNGJ LvGS6xlwQSgNpk2qXYwf8iXg7VWZAgMBAAGjQjBAMB0GA1UdDgQWBBQgIvz0bNGJ
hjgpToksyKpP9xv9oDAPBgNVHRMECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAN hjgpToksyKpP9xv9oDAPBgNVHRMECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAN
BgkqhkiG9w0BAQsFAAOCAQEAjvjuOMDSa+JXFCLyBKsycXtBVZsJ4Ue3LbaEsPY4 BgkqhkiG9w0BAQsFAAOCAQEAjvjuOMDSa+JXFCLyBKsycXtBVZsJ4Ue3LbaEsPY4
MYN/hIQ5ZM5p7EjfcnMG4CtYkNsfNHc0AhBLdq45rnT87q/6O3vUEtNMafbhU6kt MYN/hIQ5ZM5p7EjfcnMG4CtYkNsfNHc0AhBLdq45rnT87q/6O3vUEtNMafbhU6kt
hX7Y+9XFN9NpmYxr+ekVY5xOxi8h9JDIgoMP4VB1uS0aunL1IGqrNooL9mmFnL2k hX7Y+9XFN9NpmYxr+ekVY5xOxi8h9JDIgoMP4VB1uS0aunL1IGqrNooL9mmFnL2k
LVVee6/VR6C5+KSTCMCWppMuJIZII2v9o4dkoZ8Y7QRjQlLfYzd3qGtKbw7xaF1U LVVee6/VR6C5+KSTCMCWppMuJIZII2v9o4dkoZ8Y7QRjQlLfYzd3qGtKbw7xaF1U
sG/5xUb/Btwb2X2g4InpiB/yt/3CpQXpiWX/K4mBvUKiGn05ZsqeY1gx4g0xLBqc sG/5xUb/Btwb2X2g4InpiB/yt/3CpQXpiWX/K4mBvUKiGn05ZsqeY1gx4g0xLBqc
U9psmyPzK+Vsgw2jeRQ5JlKDyqE0hebfC1tvFu0CCrJFcw== U9psmyPzK+Vsgw2jeRQ5JlKDyqE0hebfC1tvFu0CCrJFcw==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,370 +1,370 @@
<?php <?php
/* /*
* Copyright (C) 2022 Lukas Buchs * Copyright (C) 2022 Lukas Buchs
* license https://github.com/lbuchs/WebAuthn/blob/master/LICENSE MIT * license https://github.com/lbuchs/WebAuthn/blob/master/LICENSE MIT
* *
* Server test script for WebAuthn library. Saves new registrations in session. * Server test script for WebAuthn library. Saves new registrations in session.
* *
* JAVASCRIPT | SERVER * JAVASCRIPT | SERVER
* ------------------------------------------------------------ * ------------------------------------------------------------
* *
* REGISTRATION * REGISTRATION
* *
* window.fetch -----------------> getCreateArgs * window.fetch -----------------> getCreateArgs
* | * |
* navigator.credentials.create <-------------' * navigator.credentials.create <-------------'
* | * |
* '-------------------------> processCreate * '-------------------------> processCreate
* | * |
* alert ok or fail <----------------' * alert ok or fail <----------------'
* *
* ------------------------------------------------------------ * ------------------------------------------------------------
* *
* VALIDATION * VALIDATION
* *
* window.fetch ------------------> getGetArgs * window.fetch ------------------> getGetArgs
* | * |
* navigator.credentials.get <----------------' * navigator.credentials.get <----------------'
* | * |
* '-------------------------> processGet * '-------------------------> processGet
* | * |
* alert ok or fail <----------------' * alert ok or fail <----------------'
* *
* ------------------------------------------------------------ * ------------------------------------------------------------
*/ */
require_once '../src/WebAuthn.php'; require_once '../src/WebAuthn.php';
try { try {
session_start(); session_start();
// read get argument and post body // read get argument and post body
$fn = filter_input(INPUT_GET, 'fn'); $fn = filter_input(INPUT_GET, 'fn');
$requireResidentKey = !!filter_input(INPUT_GET, 'requireResidentKey'); $requireResidentKey = !!filter_input(INPUT_GET, 'requireResidentKey');
$userVerification = filter_input(INPUT_GET, 'userVerification', FILTER_SANITIZE_SPECIAL_CHARS); $userVerification = filter_input(INPUT_GET, 'userVerification', FILTER_SANITIZE_SPECIAL_CHARS);
$userId = filter_input(INPUT_GET, 'userId', FILTER_SANITIZE_SPECIAL_CHARS); $userId = filter_input(INPUT_GET, 'userId', FILTER_SANITIZE_SPECIAL_CHARS);
$userName = filter_input(INPUT_GET, 'userName', FILTER_SANITIZE_SPECIAL_CHARS); $userName = filter_input(INPUT_GET, 'userName', FILTER_SANITIZE_SPECIAL_CHARS);
$userDisplayName = filter_input(INPUT_GET, 'userDisplayName', FILTER_SANITIZE_SPECIAL_CHARS); $userDisplayName = filter_input(INPUT_GET, 'userDisplayName', FILTER_SANITIZE_SPECIAL_CHARS);
$userId = $userId ? preg_replace('/[^0-9a-f]/i', '', $userId): ""; $userId = $userId ? preg_replace('/[^0-9a-f]/i', '', $userId): "";
$userName = $userName ? preg_replace('/[^0-9a-z]/i', '', $userName): ""; $userName = $userName ? preg_replace('/[^0-9a-z]/i', '', $userName): "";
$userDisplayName = $userDisplayName ? preg_replace('/[^0-9a-z öüäéèàÖÜÄÉÈÀÂÊÎÔÛâêîôû]/i', '', $userDisplayName): ""; $userDisplayName = $userDisplayName ? preg_replace('/[^0-9a-z öüäéèàÖÜÄÉÈÀÂÊÎÔÛâêîôû]/i', '', $userDisplayName): "";
$post = trim(file_get_contents('php://input')); $post = trim(file_get_contents('php://input'));
if ($post) { if ($post) {
$post = json_decode($post, null, 512, JSON_THROW_ON_ERROR); $post = json_decode($post, null, 512, JSON_THROW_ON_ERROR);
} }
if ($fn !== 'getStoredDataHtml') { if ($fn !== 'getStoredDataHtml') {
// Formats // Formats
$formats = []; $formats = [];
if (filter_input(INPUT_GET, 'fmt_android-key')) { if (filter_input(INPUT_GET, 'fmt_android-key')) {
$formats[] = 'android-key'; $formats[] = 'android-key';
} }
if (filter_input(INPUT_GET, 'fmt_android-safetynet')) { if (filter_input(INPUT_GET, 'fmt_android-safetynet')) {
$formats[] = 'android-safetynet'; $formats[] = 'android-safetynet';
} }
if (filter_input(INPUT_GET, 'fmt_apple')) { if (filter_input(INPUT_GET, 'fmt_apple')) {
$formats[] = 'apple'; $formats[] = 'apple';
} }
if (filter_input(INPUT_GET, 'fmt_fido-u2f')) { if (filter_input(INPUT_GET, 'fmt_fido-u2f')) {
$formats[] = 'fido-u2f'; $formats[] = 'fido-u2f';
} }
if (filter_input(INPUT_GET, 'fmt_none')) { if (filter_input(INPUT_GET, 'fmt_none')) {
$formats[] = 'none'; $formats[] = 'none';
} }
if (filter_input(INPUT_GET, 'fmt_packed')) { if (filter_input(INPUT_GET, 'fmt_packed')) {
$formats[] = 'packed'; $formats[] = 'packed';
} }
if (filter_input(INPUT_GET, 'fmt_tpm')) { if (filter_input(INPUT_GET, 'fmt_tpm')) {
$formats[] = 'tpm'; $formats[] = 'tpm';
} }
$rpId = 'localhost'; $rpId = 'localhost';
if (filter_input(INPUT_GET, 'rpId')) { if (filter_input(INPUT_GET, 'rpId')) {
$rpId = filter_input(INPUT_GET, 'rpId', FILTER_VALIDATE_DOMAIN); $rpId = filter_input(INPUT_GET, 'rpId', FILTER_VALIDATE_DOMAIN);
if ($rpId === false) { if ($rpId === false) {
throw new Exception('invalid relying party ID'); throw new Exception('invalid relying party ID');
} }
} }
// types selected on front end // types selected on front end
$typeUsb = !!filter_input(INPUT_GET, 'type_usb'); $typeUsb = !!filter_input(INPUT_GET, 'type_usb');
$typeNfc = !!filter_input(INPUT_GET, 'type_nfc'); $typeNfc = !!filter_input(INPUT_GET, 'type_nfc');
$typeBle = !!filter_input(INPUT_GET, 'type_ble'); $typeBle = !!filter_input(INPUT_GET, 'type_ble');
$typeInt = !!filter_input(INPUT_GET, 'type_int'); $typeInt = !!filter_input(INPUT_GET, 'type_int');
$typeHyb = !!filter_input(INPUT_GET, 'type_hybrid'); $typeHyb = !!filter_input(INPUT_GET, 'type_hybrid');
// cross-platform: true, if type internal is not allowed // cross-platform: true, if type internal is not allowed
// false, if only internal is allowed // false, if only internal is allowed
// null, if internal and cross-platform is allowed // null, if internal and cross-platform is allowed
$crossPlatformAttachment = null; $crossPlatformAttachment = null;
if (($typeUsb || $typeNfc || $typeBle || $typeHyb) && !$typeInt) { if (($typeUsb || $typeNfc || $typeBle || $typeHyb) && !$typeInt) {
$crossPlatformAttachment = true; $crossPlatformAttachment = true;
} else if (!$typeUsb && !$typeNfc && !$typeBle && !$typeHyb && $typeInt) { } else if (!$typeUsb && !$typeNfc && !$typeBle && !$typeHyb && $typeInt) {
$crossPlatformAttachment = false; $crossPlatformAttachment = false;
} }
// new Instance of the server library. // new Instance of the server library.
// make sure that $rpId is the domain name. // make sure that $rpId is the domain name.
$WebAuthn = new lbuchs\WebAuthn\WebAuthn('WebAuthn Library', $rpId, $formats); $WebAuthn = new lbuchs\WebAuthn\WebAuthn('WebAuthn Library', $rpId, $formats);
// add root certificates to validate new registrations // add root certificates to validate new registrations
if (filter_input(INPUT_GET, 'solo')) { if (filter_input(INPUT_GET, 'solo')) {
$WebAuthn->addRootCertificates('rootCertificates/solo.pem'); $WebAuthn->addRootCertificates('rootCertificates/solo.pem');
$WebAuthn->addRootCertificates('rootCertificates/solokey_f1.pem'); $WebAuthn->addRootCertificates('rootCertificates/solokey_f1.pem');
$WebAuthn->addRootCertificates('rootCertificates/solokey_r1.pem'); $WebAuthn->addRootCertificates('rootCertificates/solokey_r1.pem');
} }
if (filter_input(INPUT_GET, 'apple')) { if (filter_input(INPUT_GET, 'apple')) {
$WebAuthn->addRootCertificates('rootCertificates/apple.pem'); $WebAuthn->addRootCertificates('rootCertificates/apple.pem');
} }
if (filter_input(INPUT_GET, 'yubico')) { if (filter_input(INPUT_GET, 'yubico')) {
$WebAuthn->addRootCertificates('rootCertificates/yubico.pem'); $WebAuthn->addRootCertificates('rootCertificates/yubico.pem');
} }
if (filter_input(INPUT_GET, 'hypersecu')) { if (filter_input(INPUT_GET, 'hypersecu')) {
$WebAuthn->addRootCertificates('rootCertificates/hypersecu.pem'); $WebAuthn->addRootCertificates('rootCertificates/hypersecu.pem');
} }
if (filter_input(INPUT_GET, 'google')) { if (filter_input(INPUT_GET, 'google')) {
$WebAuthn->addRootCertificates('rootCertificates/globalSign.pem'); $WebAuthn->addRootCertificates('rootCertificates/globalSign.pem');
$WebAuthn->addRootCertificates('rootCertificates/googleHardware.pem'); $WebAuthn->addRootCertificates('rootCertificates/googleHardware.pem');
} }
if (filter_input(INPUT_GET, 'microsoft')) { if (filter_input(INPUT_GET, 'microsoft')) {
$WebAuthn->addRootCertificates('rootCertificates/microsoftTpmCollection.pem'); $WebAuthn->addRootCertificates('rootCertificates/microsoftTpmCollection.pem');
} }
if (filter_input(INPUT_GET, 'mds')) { if (filter_input(INPUT_GET, 'mds')) {
$WebAuthn->addRootCertificates('rootCertificates/mds'); $WebAuthn->addRootCertificates('rootCertificates/mds');
} }
} }
// ------------------------------------ // ------------------------------------
// request for create arguments // request for create arguments
// ------------------------------------ // ------------------------------------
if ($fn === 'getCreateArgs') { if ($fn === 'getCreateArgs') {
$createArgs = $WebAuthn->getCreateArgs(\hex2bin($userId), $userName, $userDisplayName, 60*4, $requireResidentKey, $userVerification, $crossPlatformAttachment); $createArgs = $WebAuthn->getCreateArgs(\hex2bin($userId), $userName, $userDisplayName, 60*4, $requireResidentKey, $userVerification, $crossPlatformAttachment);
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($createArgs)); print(json_encode($createArgs));
// save challange to session. you have to deliver it to processGet later. // save challange to session. you have to deliver it to processGet later.
$_SESSION['challenge'] = $WebAuthn->getChallenge(); $_SESSION['challenge'] = $WebAuthn->getChallenge();
// ------------------------------------ // ------------------------------------
// request for get arguments // request for get arguments
// ------------------------------------ // ------------------------------------
} else if ($fn === 'getGetArgs') { } else if ($fn === 'getGetArgs') {
$ids = []; $ids = [];
if ($requireResidentKey) { if ($requireResidentKey) {
if (!isset($_SESSION['registrations']) || !is_array($_SESSION['registrations']) || count($_SESSION['registrations']) === 0) { if (!isset($_SESSION['registrations']) || !is_array($_SESSION['registrations']) || count($_SESSION['registrations']) === 0) {
throw new Exception('we do not have any registrations in session to check the registration'); throw new Exception('we do not have any registrations in session to check the registration');
} }
} else { } else {
// load registrations from session stored there by processCreate. // load registrations from session stored there by processCreate.
// normaly you have to load the credential Id's for a username // normaly you have to load the credential Id's for a username
// from the database. // from the database.
if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) { if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) {
foreach ($_SESSION['registrations'] as $reg) { foreach ($_SESSION['registrations'] as $reg) {
if ($reg->userId === $userId) { if ($reg->userId === $userId) {
$ids[] = $reg->credentialId; $ids[] = $reg->credentialId;
} }
} }
} }
if (count($ids) === 0) { if (count($ids) === 0) {
throw new Exception('no registrations in session for userId ' . $userId); throw new Exception('no registrations in session for userId ' . $userId);
} }
} }
$getArgs = $WebAuthn->getGetArgs($ids, 60*4, $typeUsb, $typeNfc, $typeBle, $typeHyb, $typeInt, $userVerification); $getArgs = $WebAuthn->getGetArgs($ids, 60*4, $typeUsb, $typeNfc, $typeBle, $typeHyb, $typeInt, $userVerification);
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($getArgs)); print(json_encode($getArgs));
// save challange to session. you have to deliver it to processGet later. // save challange to session. you have to deliver it to processGet later.
$_SESSION['challenge'] = $WebAuthn->getChallenge(); $_SESSION['challenge'] = $WebAuthn->getChallenge();
// ------------------------------------ // ------------------------------------
// process create // process create
// ------------------------------------ // ------------------------------------
} else if ($fn === 'processCreate') { } else if ($fn === 'processCreate') {
$clientDataJSON = base64_decode($post->clientDataJSON); $clientDataJSON = base64_decode($post->clientDataJSON);
$attestationObject = base64_decode($post->attestationObject); $attestationObject = base64_decode($post->attestationObject);
$challenge = $_SESSION['challenge']; $challenge = $_SESSION['challenge'];
// processCreate returns data to be stored for future logins. // processCreate returns data to be stored for future logins.
// in this example we store it in the php session. // in this example we store it in the php session.
// Normaly you have to store the data in a database connected // Normaly you have to store the data in a database connected
// with the user name. // with the user name.
$data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $challenge, $userVerification === 'required', true, false); $data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $challenge, $userVerification === 'required', true, false);
// add user infos // add user infos
$data->userId = $userId; $data->userId = $userId;
$data->userName = $userName; $data->userName = $userName;
$data->userDisplayName = $userDisplayName; $data->userDisplayName = $userDisplayName;
if (!isset($_SESSION['registrations']) || !array_key_exists('registrations', $_SESSION) || !is_array($_SESSION['registrations'])) { if (!isset($_SESSION['registrations']) || !array_key_exists('registrations', $_SESSION) || !is_array($_SESSION['registrations'])) {
$_SESSION['registrations'] = []; $_SESSION['registrations'] = [];
} }
$_SESSION['registrations'][] = $data; $_SESSION['registrations'][] = $data;
$msg = 'registration success.'; $msg = 'registration success.';
if ($data->rootValid === false) { if ($data->rootValid === false) {
$msg = 'registration ok, but certificate does not match any of the selected root ca.'; $msg = 'registration ok, but certificate does not match any of the selected root ca.';
} }
$return = new stdClass(); $return = new stdClass();
$return->success = true; $return->success = true;
$return->msg = $msg; $return->msg = $msg;
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($return)); print(json_encode($return));
// ------------------------------------ // ------------------------------------
// proccess get // proccess get
// ------------------------------------ // ------------------------------------
} else if ($fn === 'processGet') { } else if ($fn === 'processGet') {
$clientDataJSON = base64_decode($post->clientDataJSON); $clientDataJSON = base64_decode($post->clientDataJSON);
$authenticatorData = base64_decode($post->authenticatorData); $authenticatorData = base64_decode($post->authenticatorData);
$signature = base64_decode($post->signature); $signature = base64_decode($post->signature);
$userHandle = base64_decode($post->userHandle); $userHandle = base64_decode($post->userHandle);
$id = base64_decode($post->id); $id = base64_decode($post->id);
$challenge = $_SESSION['challenge'] ?? ''; $challenge = $_SESSION['challenge'] ?? '';
$credentialPublicKey = null; $credentialPublicKey = null;
// looking up correspondending public key of the credential id // looking up correspondending public key of the credential id
// you should also validate that only ids of the given user name // you should also validate that only ids of the given user name
// are taken for the login. // are taken for the login.
if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) { if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) {
foreach ($_SESSION['registrations'] as $reg) { foreach ($_SESSION['registrations'] as $reg) {
if ($reg->credentialId === $id) { if ($reg->credentialId === $id) {
$credentialPublicKey = $reg->credentialPublicKey; $credentialPublicKey = $reg->credentialPublicKey;
break; break;
} }
} }
} }
if ($credentialPublicKey === null) { if ($credentialPublicKey === null) {
throw new Exception('Public Key for credential ID not found!'); throw new Exception('Public Key for credential ID not found!');
} }
// if we have resident key, we have to verify that the userHandle is the provided userId at registration // if we have resident key, we have to verify that the userHandle is the provided userId at registration
if ($requireResidentKey && $userHandle !== hex2bin($reg->userId)) { if ($requireResidentKey && $userHandle !== hex2bin($reg->userId)) {
throw new \Exception('userId doesnt match (is ' . bin2hex($userHandle) . ' but expect ' . $reg->userId . ')'); throw new \Exception('userId doesnt match (is ' . bin2hex($userHandle) . ' but expect ' . $reg->userId . ')');
} }
// process the get request. throws WebAuthnException if it fails // process the get request. throws WebAuthnException if it fails
$WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $credentialPublicKey, $challenge, null, $userVerification === 'required'); $WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $credentialPublicKey, $challenge, null, $userVerification === 'required');
$return = new stdClass(); $return = new stdClass();
$return->success = true; $return->success = true;
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($return)); print(json_encode($return));
// ------------------------------------ // ------------------------------------
// proccess clear registrations // proccess clear registrations
// ------------------------------------ // ------------------------------------
} else if ($fn === 'clearRegistrations') { } else if ($fn === 'clearRegistrations') {
$_SESSION['registrations'] = null; $_SESSION['registrations'] = null;
$_SESSION['challenge'] = null; $_SESSION['challenge'] = null;
$return = new stdClass(); $return = new stdClass();
$return->success = true; $return->success = true;
$return->msg = 'all registrations deleted'; $return->msg = 'all registrations deleted';
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($return)); print(json_encode($return));
// ------------------------------------ // ------------------------------------
// display stored data as HTML // display stored data as HTML
// ------------------------------------ // ------------------------------------
} else if ($fn === 'getStoredDataHtml') { } else if ($fn === 'getStoredDataHtml') {
$html = '<!DOCTYPE html>' . "\n"; $html = '<!DOCTYPE html>' . "\n";
$html .= '<html><head><style>tr:nth-child(even){background-color: #f2f2f2;}</style></head>'; $html .= '<html><head><style>tr:nth-child(even){background-color: #f2f2f2;}</style></head>';
$html .= '<body style="font-family:sans-serif">'; $html .= '<body style="font-family:sans-serif">';
if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) { if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) {
$html .= '<p>There are ' . count($_SESSION['registrations']) . ' registrations in this session:</p>'; $html .= '<p>There are ' . count($_SESSION['registrations']) . ' registrations in this session:</p>';
foreach ($_SESSION['registrations'] as $reg) { foreach ($_SESSION['registrations'] as $reg) {
$html .= '<table style="border:1px solid black;margin:10px 0;">'; $html .= '<table style="border:1px solid black;margin:10px 0;">';
foreach ($reg as $key => $value) { foreach ($reg as $key => $value) {
if (is_bool($value)) { if (is_bool($value)) {
$value = $value ? 'yes' : 'no'; $value = $value ? 'yes' : 'no';
} else if (is_null($value)) { } else if (is_null($value)) {
$value = 'null'; $value = 'null';
} else if (is_object($value)) { } else if (is_object($value)) {
$value = chunk_split(strval($value), 64); $value = chunk_split(strval($value), 64);
} else if (is_string($value) && strlen($value) > 0 && htmlspecialchars($value, ENT_QUOTES) === '') { } else if (is_string($value) && strlen($value) > 0 && htmlspecialchars($value, ENT_QUOTES) === '') {
$value = chunk_split(bin2hex($value), 64); $value = chunk_split(bin2hex($value), 64);
} }
$html .= '<tr><td>' . htmlspecialchars($key) . '</td><td style="font-family:monospace;">' . nl2br(htmlspecialchars($value)) . '</td>'; $html .= '<tr><td>' . htmlspecialchars($key) . '</td><td style="font-family:monospace;">' . nl2br(htmlspecialchars($value)) . '</td>';
} }
$html .= '</table>'; $html .= '</table>';
} }
} else { } else {
$html .= '<p>There are no registrations in this session.</p>'; $html .= '<p>There are no registrations in this session.</p>';
} }
$html .= '</body></html>'; $html .= '</body></html>';
header('Content-Type: text/html'); header('Content-Type: text/html');
print $html; print $html;
// ------------------------------------ // ------------------------------------
// get root certs from FIDO Alliance Metadata Service // get root certs from FIDO Alliance Metadata Service
// ------------------------------------ // ------------------------------------
} else if ($fn === 'queryFidoMetaDataService') { } else if ($fn === 'queryFidoMetaDataService') {
$mdsFolder = 'rootCertificates/mds'; $mdsFolder = 'rootCertificates/mds';
$success = false; $success = false;
$msg = null; $msg = null;
// fetch only 1x / 24h // fetch only 1x / 24h
$lastFetch = \is_file($mdsFolder . '/lastMdsFetch.txt') ? \strtotime(\file_get_contents($mdsFolder . '/lastMdsFetch.txt')) : 0; $lastFetch = \is_file($mdsFolder . '/lastMdsFetch.txt') ? \strtotime(\file_get_contents($mdsFolder . '/lastMdsFetch.txt')) : 0;
if ($lastFetch + (3600*48) < \time()) { if ($lastFetch + (3600*48) < \time()) {
$cnt = $WebAuthn->queryFidoMetaDataService($mdsFolder); $cnt = $WebAuthn->queryFidoMetaDataService($mdsFolder);
$success = true; $success = true;
\file_put_contents($mdsFolder . '/lastMdsFetch.txt', date('r')); \file_put_contents($mdsFolder . '/lastMdsFetch.txt', date('r'));
$msg = 'successfully queried FIDO Alliance Metadata Service - ' . $cnt . ' certificates downloaded.'; $msg = 'successfully queried FIDO Alliance Metadata Service - ' . $cnt . ' certificates downloaded.';
} else { } else {
$msg = 'Fail: last fetch was at ' . date('r', $lastFetch) . ' - fetch only 1x every 48h'; $msg = 'Fail: last fetch was at ' . date('r', $lastFetch) . ' - fetch only 1x every 48h';
} }
$return = new stdClass(); $return = new stdClass();
$return->success = $success; $return->success = $success;
$return->msg = $msg; $return->msg = $msg;
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($return)); print(json_encode($return));
} }
} catch (Throwable $ex) { } catch (Throwable $ex) {
$return = new stdClass(); $return = new stdClass();
$return->success = false; $return->success = false;
$return->msg = $ex->getMessage(); $return->msg = $ex->getMessage();
header('Content-Type: application/json'); header('Content-Type: application/json');
print(json_encode($return)); print(json_encode($return));
} }

View File

@ -1,23 +1,23 @@
{ {
"name": "lbuchs/webauthn", "name": "lbuchs/webauthn",
"description": "A simple PHP WebAuthn (FIDO2) server library", "description": "A simple PHP WebAuthn (FIDO2) server library",
"keywords": [ "keywords": [
"webauthn", "authentication" "webauthn", "authentication"
], ],
"homepage": "https://github.com/lbuchs/webauthn", "homepage": "https://github.com/lbuchs/webauthn",
"license": "MIT", "license": "MIT",
"authors": [ "authors": [
{ {
"name": "Lukas Buchs", "name": "Lukas Buchs",
"role": "Developer" "role": "Developer"
} }
], ],
"require": { "require": {
"php" : ">=8.0.0" "php" : ">=8.0.0"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"lbuchs\\WebAuthn\\": "src" "lbuchs\\WebAuthn\\": "src"
} }
} }
} }

View File

@ -1,18 +1,18 @@
ACS FIDO Authenticator ACS FIDO Authenticator
---------------------- ----------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICQTCCAeegAwIBAgIUF/0wTPP6FEqxpsibJiLFtDj4qhwwCgYIKoZIzj0EAwIw MIICQTCCAeegAwIBAgIUF/0wTPP6FEqxpsibJiLFtDj4qhwwCgYIKoZIzj0EAwIw
dTELMAkGA1UEBhMCSEsxEjAQBgNVBAgMCUhvbmcgS29uZzESMBAGA1UEBwwJSG9u dTELMAkGA1UEBhMCSEsxEjAQBgNVBAgMCUhvbmcgS29uZzESMBAGA1UEBwwJSG9u
ZyBLb25nMSMwIQYDVQQKDBpBZHZhbmNlZCBDYXJkIFN5c3RlbXMgTHRkLjEZMBcG ZyBLb25nMSMwIQYDVQQKDBpBZHZhbmNlZCBDYXJkIFN5c3RlbXMgTHRkLjEZMBcG
A1UEAwwQQUNTIEZJRE8gUm9vdCBDQTAgFw0yMjA1MzAwOTIzMzVaGA8yMDUyMDUy A1UEAwwQQUNTIEZJRE8gUm9vdCBDQTAgFw0yMjA1MzAwOTIzMzVaGA8yMDUyMDUy
MjA5MjMzNVowdTELMAkGA1UEBhMCSEsxEjAQBgNVBAgMCUhvbmcgS29uZzESMBAG MjA5MjMzNVowdTELMAkGA1UEBhMCSEsxEjAQBgNVBAgMCUhvbmcgS29uZzESMBAG
A1UEBwwJSG9uZyBLb25nMSMwIQYDVQQKDBpBZHZhbmNlZCBDYXJkIFN5c3RlbXMg A1UEBwwJSG9uZyBLb25nMSMwIQYDVQQKDBpBZHZhbmNlZCBDYXJkIFN5c3RlbXMg
THRkLjEZMBcGA1UEAwwQQUNTIEZJRE8gUm9vdCBDQTBZMBMGByqGSM49AgEGCCqG THRkLjEZMBcGA1UEAwwQQUNTIEZJRE8gUm9vdCBDQTBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABBwYgKVwjCV6+lv7gnpFERzU2uND8gdEkPCNcs/vFDs2sK42Juxn SM49AwEHA0IABBwYgKVwjCV6+lv7gnpFERzU2uND8gdEkPCNcs/vFDs2sK42Juxn
hFnIgMB2DyU0IrXILjf/2XT0YSTd1sPiTSajUzBRMB0GA1UdDgQWBBTnQarpdSt4 hFnIgMB2DyU0IrXILjf/2XT0YSTd1sPiTSajUzBRMB0GA1UdDgQWBBTnQarpdSt4
sid7VjfNILIHrb2PoDAfBgNVHSMEGDAWgBTnQarpdSt4sid7VjfNILIHrb2PoDAP sid7VjfNILIHrb2PoDAfBgNVHSMEGDAWgBTnQarpdSt4sid7VjfNILIHrb2PoDAP
BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDcoXJ3rzNMA/fZkh08 BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDcoXJ3rzNMA/fZkh08
PoFrMx43GYMhZMfLPw/3MfJpGAIgectKwmJYM9J8SX8x/aQV4iGvKWoBfr1XPTAM PoFrMx43GYMhZMfLPw/3MfJpGAIgectKwmJYM9J8SX8x/aQV4iGvKWoBfr1XPTAM
XOhVEYE= XOhVEYE=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,18 +1,18 @@
ACS FIDO Authenticator Card ACS FIDO Authenticator Card
--------------------------- ---------------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICQTCCAeegAwIBAgIUF/0wTPP6FEqxpsibJiLFtDj4qhwwCgYIKoZIzj0EAwIw MIICQTCCAeegAwIBAgIUF/0wTPP6FEqxpsibJiLFtDj4qhwwCgYIKoZIzj0EAwIw
dTELMAkGA1UEBhMCSEsxEjAQBgNVBAgMCUhvbmcgS29uZzESMBAGA1UEBwwJSG9u dTELMAkGA1UEBhMCSEsxEjAQBgNVBAgMCUhvbmcgS29uZzESMBAGA1UEBwwJSG9u
ZyBLb25nMSMwIQYDVQQKDBpBZHZhbmNlZCBDYXJkIFN5c3RlbXMgTHRkLjEZMBcG ZyBLb25nMSMwIQYDVQQKDBpBZHZhbmNlZCBDYXJkIFN5c3RlbXMgTHRkLjEZMBcG
A1UEAwwQQUNTIEZJRE8gUm9vdCBDQTAgFw0yMjA1MzAwOTIzMzVaGA8yMDUyMDUy A1UEAwwQQUNTIEZJRE8gUm9vdCBDQTAgFw0yMjA1MzAwOTIzMzVaGA8yMDUyMDUy
MjA5MjMzNVowdTELMAkGA1UEBhMCSEsxEjAQBgNVBAgMCUhvbmcgS29uZzESMBAG MjA5MjMzNVowdTELMAkGA1UEBhMCSEsxEjAQBgNVBAgMCUhvbmcgS29uZzESMBAG
A1UEBwwJSG9uZyBLb25nMSMwIQYDVQQKDBpBZHZhbmNlZCBDYXJkIFN5c3RlbXMg A1UEBwwJSG9uZyBLb25nMSMwIQYDVQQKDBpBZHZhbmNlZCBDYXJkIFN5c3RlbXMg
THRkLjEZMBcGA1UEAwwQQUNTIEZJRE8gUm9vdCBDQTBZMBMGByqGSM49AgEGCCqG THRkLjEZMBcGA1UEAwwQQUNTIEZJRE8gUm9vdCBDQTBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABBwYgKVwjCV6+lv7gnpFERzU2uND8gdEkPCNcs/vFDs2sK42Juxn SM49AwEHA0IABBwYgKVwjCV6+lv7gnpFERzU2uND8gdEkPCNcs/vFDs2sK42Juxn
hFnIgMB2DyU0IrXILjf/2XT0YSTd1sPiTSajUzBRMB0GA1UdDgQWBBTnQarpdSt4 hFnIgMB2DyU0IrXILjf/2XT0YSTd1sPiTSajUzBRMB0GA1UdDgQWBBTnQarpdSt4
sid7VjfNILIHrb2PoDAfBgNVHSMEGDAWgBTnQarpdSt4sid7VjfNILIHrb2PoDAP sid7VjfNILIHrb2PoDAfBgNVHSMEGDAWgBTnQarpdSt4sid7VjfNILIHrb2PoDAP
BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDcoXJ3rzNMA/fZkh08 BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDcoXJ3rzNMA/fZkh08
PoFrMx43GYMhZMfLPw/3MfJpGAIgectKwmJYM9J8SX8x/aQV4iGvKWoBfr1XPTAM PoFrMx43GYMhZMfLPw/3MfJpGAIgectKwmJYM9J8SX8x/aQV4iGvKWoBfr1XPTAM
XOhVEYE= XOhVEYE=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,19 +1,19 @@
ACS FIDO Authenticator NFC ACS FIDO Authenticator NFC
-------------------------- --------------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICfzCCAiWgAwIBAgIFEIZAB3MwCgYIKoZIzj0EAwIwdTELMAkGA1UEBhMCSEsx MIICfzCCAiWgAwIBAgIFEIZAB3MwCgYIKoZIzj0EAwIwdTELMAkGA1UEBhMCSEsx
EjAQBgNVBAgMCUhvbmcgS29uZzESMBAGA1UEBwwJSG9uZyBLb25nMSMwIQYDVQQK EjAQBgNVBAgMCUhvbmcgS29uZzESMBAGA1UEBwwJSG9uZyBLb25nMSMwIQYDVQQK
DBpBZHZhbmNlZCBDYXJkIFN5c3RlbXMgTHRkLjEZMBcGA1UEAwwQQUNTIEZJRE8g DBpBZHZhbmNlZCBDYXJkIFN5c3RlbXMgTHRkLjEZMBcGA1UEAwwQQUNTIEZJRE8g
Um9vdCBDQTAeFw0yNDEwMDMwNjQ2MzZaFw0zNDEwMDMwNjQ2MzZaMIGCMQswCQYD Um9vdCBDQTAeFw0yNDEwMDMwNjQ2MzZaFw0zNDEwMDMwNjQ2MzZaMIGCMQswCQYD
VQQGEwJISzEjMCEGA1UECgwaQWR2YW5jZWQgQ2FyZCBTeXN0ZW1zIEx0ZC4xIjAg VQQGEwJISzEjMCEGA1UECgwaQWR2YW5jZWQgQ2FyZCBTeXN0ZW1zIEx0ZC4xIjAg
BgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xKjAoBgNVBAMMIUFDUyBB BgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xKjAoBgNVBAMMIUFDUyBB
RkQwMyBBdHRlc3RhdGlvbiBDZXJ0aWZpY2F0ZTBZMBMGByqGSM49AgEGCCqGSM49 RkQwMyBBdHRlc3RhdGlvbiBDZXJ0aWZpY2F0ZTBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABGseNayIOV4mfqT3QSoL4xWCaGLciKA0oAciih1uHjT6oWCM7x/AQcHj AwEHA0IABGseNayIOV4mfqT3QSoL4xWCaGLciKA0oAciih1uHjT6oWCM7x/AQcHj
bBhdGne52Jqi99Ye3aqkq+LkdvP/M/WjgZMwgZAwCQYDVR0TBAIwADALBgNVHQ8E bBhdGne52Jqi99Ye3aqkq+LkdvP/M/WjgZMwgZAwCQYDVR0TBAIwADALBgNVHQ8E
BAMCBsAwEwYLKwYBBAGC5RwCAQEEBAMCBDAwIQYLKwYBBAGC5RwBAQQEEgQQyJ5q BAMCBsAwEwYLKwYBBAGC5RwCAQEEBAMCBDAwIQYLKwYBBAGC5RwBAQQEEgQQyJ5q
OGwAVCZapcnL9I8DgjAdBgNVHQ4EFgQUG6zB4SX9RFX0SvNyAHzTvKZhGSUwHwYD OGwAVCZapcnL9I8DgjAdBgNVHQ4EFgQUG6zB4SX9RFX0SvNyAHzTvKZhGSUwHwYD
VR0jBBgwFoAU50Gq6XUreLIne1Y3zSCyB629j6AwCgYIKoZIzj0EAwIDSAAwRQIh VR0jBBgwFoAU50Gq6XUreLIne1Y3zSCyB629j6AwCgYIKoZIzj0EAwIDSAAwRQIh
AIm78GC7xl0VIvQjh7E4+AIH0Pw424oduUUgdwWonG40AiAx1X6XmXBr5b1jmpCY AIm78GC7xl0VIvQjh7E4+AIH0Pw424oduUUgdwWonG40AiAx1X6XmXBr5b1jmpCY
cvLMfdH9ObP3EklIXU9FHgLosA== cvLMfdH9ObP3EklIXU9FHgLosA==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,20 +1,20 @@
Allthenticator Android App: roaming BLE FIDO2 Allthenticator for Windows, Mac, Linux, and Allthenticate door readers Allthenticator Android App: roaming BLE FIDO2 Allthenticator for Windows, Mac, Linux, and Allthenticate door readers
-------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICqDCCAk6gAwIBAgIUGFCc6rhe4EiRa/OSqPNwuoR2jkQwCgYIKoZIzj0EAwIw MIICqDCCAk6gAwIBAgIUGFCc6rhe4EiRa/OSqPNwuoR2jkQwCgYIKoZIzj0EAwIw
gaoxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3Rv gaoxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3Rv
bjEWMBQGA1UECgwNQWxsdGhlbnRpY2F0ZTEiMCAGA1UECwwZQXV0aGVudGljYXRv bjEWMBQGA1UECgwNQWxsdGhlbnRpY2F0ZTEiMCAGA1UECwwZQXV0aGVudGljYXRv
ciBBdHRlc3RhdGlvbjEWMBQGA1UEAwwNQWxsdGhlbnRpY2F0ZTElMCMGCSqGSIb3 ciBBdHRlc3RhdGlvbjEWMBQGA1UEAwwNQWxsdGhlbnRpY2F0ZTElMCMGCSqGSIb3
DQEJARYWaGVscEBhbGx0aGVudGljYXRlLmNvbTAeFw0yNDAzMTQxNTUyNTJaFw0z DQEJARYWaGVscEBhbGx0aGVudGljYXRlLmNvbTAeFw0yNDAzMTQxNTUyNTJaFw0z
NDAzMTIxNTUyNTJaMIGqMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO NDAzMTIxNTUyNTJaMIGqMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO
BgNVBAcMB0hvdXN0b24xFjAUBgNVBAoMDUFsbHRoZW50aWNhdGUxIjAgBgNVBAsM BgNVBAcMB0hvdXN0b24xFjAUBgNVBAoMDUFsbHRoZW50aWNhdGUxIjAgBgNVBAsM
GUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xFjAUBgNVBAMMDUFsbHRoZW50aWNh GUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xFjAUBgNVBAMMDUFsbHRoZW50aWNh
dGUxJTAjBgkqhkiG9w0BCQEWFmhlbHBAYWxsdGhlbnRpY2F0ZS5jb20wWTATBgcq dGUxJTAjBgkqhkiG9w0BCQEWFmhlbHBAYWxsdGhlbnRpY2F0ZS5jb20wWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAAS2IAC5t3iERq5xpsEAyqPzjTb+ekx++5Z4Vu6Y hkjOPQIBBggqhkjOPQMBBwNCAAS2IAC5t3iERq5xpsEAyqPzjTb+ekx++5Z4Vu6Y
rm7SFftzc5BdUVi7qnJpZotId2GfFjad0ZjkIf8T5R5htdVLo1AwTjAdBgNVHQ4E rm7SFftzc5BdUVi7qnJpZotId2GfFjad0ZjkIf8T5R5htdVLo1AwTjAdBgNVHQ4E
FgQUAy5QOmItkBx+RgFn4EflQVYfn1EwHwYDVR0jBBgwFoAUAy5QOmItkBx+RgFn FgQUAy5QOmItkBx+RgFn4EflQVYfn1EwHwYDVR0jBBgwFoAUAy5QOmItkBx+RgFn
4EflQVYfn1EwDAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNIADBFAiEAwsJai8gk 4EflQVYfn1EwDAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNIADBFAiEAwsJai8gk
A18gw+aLmTKww0OJNydgN4ozeKe957rRm60CIEgwALnBQkr1AFITibJJ+TDPP2yL A18gw+aLmTKww0OJNydgN4ozeKe957rRm60CIEgwALnBQkr1AFITibJJ+TDPP2yL
5no6HdTEACA7mHwH 5no6HdTEACA7mHwH
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,20 +1,20 @@
Allthenticator iOS App: roaming BLE FIDO2 Allthenticator for Windows, Mac, Linux, and Allthenticate door readers Allthenticator iOS App: roaming BLE FIDO2 Allthenticator for Windows, Mac, Linux, and Allthenticate door readers
---------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICqDCCAk6gAwIBAgIUGFCc6rhe4EiRa/OSqPNwuoR2jkQwCgYIKoZIzj0EAwIw MIICqDCCAk6gAwIBAgIUGFCc6rhe4EiRa/OSqPNwuoR2jkQwCgYIKoZIzj0EAwIw
gaoxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3Rv gaoxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3Rv
bjEWMBQGA1UECgwNQWxsdGhlbnRpY2F0ZTEiMCAGA1UECwwZQXV0aGVudGljYXRv bjEWMBQGA1UECgwNQWxsdGhlbnRpY2F0ZTEiMCAGA1UECwwZQXV0aGVudGljYXRv
ciBBdHRlc3RhdGlvbjEWMBQGA1UEAwwNQWxsdGhlbnRpY2F0ZTElMCMGCSqGSIb3 ciBBdHRlc3RhdGlvbjEWMBQGA1UEAwwNQWxsdGhlbnRpY2F0ZTElMCMGCSqGSIb3
DQEJARYWaGVscEBhbGx0aGVudGljYXRlLmNvbTAeFw0yNDAzMTQxNTUyNTJaFw0z DQEJARYWaGVscEBhbGx0aGVudGljYXRlLmNvbTAeFw0yNDAzMTQxNTUyNTJaFw0z
NDAzMTIxNTUyNTJaMIGqMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO NDAzMTIxNTUyNTJaMIGqMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO
BgNVBAcMB0hvdXN0b24xFjAUBgNVBAoMDUFsbHRoZW50aWNhdGUxIjAgBgNVBAsM BgNVBAcMB0hvdXN0b24xFjAUBgNVBAoMDUFsbHRoZW50aWNhdGUxIjAgBgNVBAsM
GUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xFjAUBgNVBAMMDUFsbHRoZW50aWNh GUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xFjAUBgNVBAMMDUFsbHRoZW50aWNh
dGUxJTAjBgkqhkiG9w0BCQEWFmhlbHBAYWxsdGhlbnRpY2F0ZS5jb20wWTATBgcq dGUxJTAjBgkqhkiG9w0BCQEWFmhlbHBAYWxsdGhlbnRpY2F0ZS5jb20wWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAAS2IAC5t3iERq5xpsEAyqPzjTb+ekx++5Z4Vu6Y hkjOPQIBBggqhkjOPQMBBwNCAAS2IAC5t3iERq5xpsEAyqPzjTb+ekx++5Z4Vu6Y
rm7SFftzc5BdUVi7qnJpZotId2GfFjad0ZjkIf8T5R5htdVLo1AwTjAdBgNVHQ4E rm7SFftzc5BdUVi7qnJpZotId2GfFjad0ZjkIf8T5R5htdVLo1AwTjAdBgNVHQ4E
FgQUAy5QOmItkBx+RgFn4EflQVYfn1EwHwYDVR0jBBgwFoAUAy5QOmItkBx+RgFn FgQUAy5QOmItkBx+RgFn4EflQVYfn1EwHwYDVR0jBBgwFoAUAy5QOmItkBx+RgFn
4EflQVYfn1EwDAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNIADBFAiEAwsJai8gk 4EflQVYfn1EwDAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNIADBFAiEAwsJai8gk
A18gw+aLmTKww0OJNydgN4ozeKe957rRm60CIEgwALnBQkr1AFITibJJ+TDPP2yL A18gw+aLmTKww0OJNydgN4ozeKe957rRm60CIEgwALnBQkr1AFITibJJ+TDPP2yL
5no6HdTEACA7mHwH 5no6HdTEACA7mHwH
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,40 +1,40 @@
Arculus FIDO2/U2F Key Card Arculus FIDO2/U2F Key Card
-------------------------- --------------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIC+jCCAqCgAwIBAgIUTXJy28lpQVlhIp7ETBi+U4bcaD8wCgYIKoZIzj0EAwIw MIIC+jCCAqCgAwIBAgIUTXJy28lpQVlhIp7ETBi+U4bcaD8wCgYIKoZIzj0EAwIw
gYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApOZXcgSmVyc2V5MREwDwYDVQQHDAhT gYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApOZXcgSmVyc2V5MREwDwYDVQQHDAhT
b21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1cmUxEDAOBgNVBAsMB0FyY3VsdXMx b21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1cmUxEDAOBgNVBAsMB0FyY3VsdXMx
ITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8tQ0EtUm9vdDAgFw0yMzA0MTgxNTQ1 ITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8tQ0EtUm9vdDAgFw0yMzA0MTgxNTQ1
NTBaGA8yMDUzMDQxMDE1NDU1MFowgYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApO NTBaGA8yMDUzMDQxMDE1NDU1MFowgYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApO
ZXcgSmVyc2V5MREwDwYDVQQHDAhTb21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1 ZXcgSmVyc2V5MREwDwYDVQQHDAhTb21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1
cmUxEDAOBgNVBAsMB0FyY3VsdXMxITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8t cmUxEDAOBgNVBAsMB0FyY3VsdXMxITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8t
Q0EtUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCgG7r6VA/h+BynUnyDZ Q0EtUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCgG7r6VA/h+BynUnyDZ
MD0VZkYW6RGnph0w25gQDWMoqAaiUaFG5MClkhakIBpLF+6xJBhO1gs+7C1k/juV MD0VZkYW6RGnph0w25gQDWMoqAaiUaFG5MClkhakIBpLF+6xJBhO1gs+7C1k/juV
uv2jgfMwgfAwHQYDVR0OBBYEFJz1gFtTTBNfffDKvdjpUEyp70ztMIHABgNVHSME uv2jgfMwgfAwHQYDVR0OBBYEFJz1gFtTTBNfffDKvdjpUEyp70ztMIHABgNVHSME
gbgwgbWAFJz1gFtTTBNfffDKvdjpUEyp70ztoYGGpIGDMIGAMQswCQYDVQQGEwJV gbgwgbWAFJz1gFtTTBNfffDKvdjpUEyp70ztoYGGpIGDMIGAMQswCQYDVQQGEwJV
UzETMBEGA1UECAwKTmV3IEplcnNleTERMA8GA1UEBwwIU29tZXJzZXQxFDASBgNV UzETMBEGA1UECAwKTmV3IEplcnNleTERMA8GA1UEBwwIU29tZXJzZXQxFDASBgNV
BAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQLDAdBcmN1bHVzMSEwHwYDVQQDDBhDb21w BAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQLDAdBcmN1bHVzMSEwHwYDVQQDDBhDb21w
b1NlY3VyZS1GSURPLUNBLVJvb3SCFE1yctvJaUFZYSKexEwYvlOG3Gg/MAwGA1Ud b1NlY3VyZS1GSURPLUNBLVJvb3SCFE1yctvJaUFZYSKexEwYvlOG3Gg/MAwGA1Ud
EwQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgcgXGMDP2rfh4ETY9EJLwuXo1S9Ui EwQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgcgXGMDP2rfh4ETY9EJLwuXo1S9Ui
qtEmPhq9/diS0nACIQDoyLZosx8rRAF1vpRXcsVQDDSHoEs/PbmF3Er/mJ0x6w== qtEmPhq9/diS0nACIQDoyLZosx8rRAF1vpRXcsVQDDSHoEs/PbmF3Er/mJ0x6w==
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIC5DCCAoqgAwIBAgIJAJ1mgX+TKiH7MAoGCCqGSM49BAMCMIGAMQswCQYDVQQG MIIC5DCCAoqgAwIBAgIJAJ1mgX+TKiH7MAoGCCqGSM49BAMCMIGAMQswCQYDVQQG
EwJVUzETMBEGA1UECAwKTmV3IEplcnNleTERMA8GA1UEBwwIU29tZXJzZXQxFDAS EwJVUzETMBEGA1UECAwKTmV3IEplcnNleTERMA8GA1UEBwwIU29tZXJzZXQxFDAS
BgNVBAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQLDAdBcmN1bHVzMSEwHwYDVQQDDBhD BgNVBAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQLDAdBcmN1bHVzMSEwHwYDVQQDDBhD
b21wb1NlY3VyZS1GSURPLUNBLVJvb3QwIBcNMjMwMTEzMTc1NTMwWhgPMjA1MzAx b21wb1NlY3VyZS1GSURPLUNBLVJvb3QwIBcNMjMwMTEzMTc1NTMwWhgPMjA1MzAx
MDUxNzU1MzBaMIGAMQswCQYDVQQGEwJVUzETMBEGA1UECAwKTmV3IEplcnNleTER MDUxNzU1MzBaMIGAMQswCQYDVQQGEwJVUzETMBEGA1UECAwKTmV3IEplcnNleTER
MA8GA1UEBwwIU29tZXJzZXQxFDASBgNVBAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQL MA8GA1UEBwwIU29tZXJzZXQxFDASBgNVBAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQL
DAdBcmN1bHVzMSEwHwYDVQQDDBhDb21wb1NlY3VyZS1GSURPLUNBLVJvb3QwWTAT DAdBcmN1bHVzMSEwHwYDVQQDDBhDb21wb1NlY3VyZS1GSURPLUNBLVJvb3QwWTAT
BgcqhkjOPQIBBggqhkjOPQMBBwNCAAR3NlslpEpX/BiZ9RpWE+qrm2IRMLi3bksd BgcqhkjOPQIBBggqhkjOPQMBBwNCAAR3NlslpEpX/BiZ9RpWE+qrm2IRMLi3bksd
aHSpA8+ozUaFavT4L0pPSLBhnTRF15CaTHJMcEUGugr/xoGTdLNpo4HoMIHlMB0G aHSpA8+ozUaFavT4L0pPSLBhnTRF15CaTHJMcEUGugr/xoGTdLNpo4HoMIHlMB0G
A1UdDgQWBBR4z78sTmaiwHBw0fzV66W6fl/9WDCBtQYDVR0jBIGtMIGqgBR4z78s A1UdDgQWBBR4z78sTmaiwHBw0fzV66W6fl/9WDCBtQYDVR0jBIGtMIGqgBR4z78s
TmaiwHBw0fzV66W6fl/9WKGBhqSBgzCBgDELMAkGA1UEBhMCVVMxEzARBgNVBAgM TmaiwHBw0fzV66W6fl/9WKGBhqSBgzCBgDELMAkGA1UEBhMCVVMxEzARBgNVBAgM
Ck5ldyBKZXJzZXkxETAPBgNVBAcMCFNvbWVyc2V0MRQwEgYDVQQKDAtDb21wb1Nl Ck5ldyBKZXJzZXkxETAPBgNVBAcMCFNvbWVyc2V0MRQwEgYDVQQKDAtDb21wb1Nl
Y3VyZTEQMA4GA1UECwwHQXJjdWx1czEhMB8GA1UEAwwYQ29tcG9TZWN1cmUtRklE Y3VyZTEQMA4GA1UECwwHQXJjdWx1czEhMB8GA1UEAwwYQ29tcG9TZWN1cmUtRklE
Ty1DQS1Sb290ggkAnWaBf5MqIfswDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQDAgNI Ty1DQS1Sb290ggkAnWaBf5MqIfswDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQDAgNI
ADBFAiBpeKFNvzFvn+zY8cQdmFGrtl01Jxyllavlqxutc2xtRgIhAO01eFsUvTDd ADBFAiBpeKFNvzFvn+zY8cQdmFGrtl01Jxyllavlqxutc2xtRgIhAO01eFsUvTDd
kTeHm9eAvwLP5vXNIrU3MOxjwaIltaOY kTeHm9eAvwLP5vXNIrU3MOxjwaIltaOY
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,21 +1,21 @@
Arculus FIDO2/U2F Key Card [P71] Arculus FIDO2/U2F Key Card [P71]
-------------------------------- --------------------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIC+jCCAqCgAwIBAgIUTXJy28lpQVlhIp7ETBi+U4bcaD8wCgYIKoZIzj0EAwIw MIIC+jCCAqCgAwIBAgIUTXJy28lpQVlhIp7ETBi+U4bcaD8wCgYIKoZIzj0EAwIw
gYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApOZXcgSmVyc2V5MREwDwYDVQQHDAhT gYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApOZXcgSmVyc2V5MREwDwYDVQQHDAhT
b21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1cmUxEDAOBgNVBAsMB0FyY3VsdXMx b21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1cmUxEDAOBgNVBAsMB0FyY3VsdXMx
ITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8tQ0EtUm9vdDAgFw0yMzA0MTgxNTQ1 ITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8tQ0EtUm9vdDAgFw0yMzA0MTgxNTQ1
NTBaGA8yMDUzMDQxMDE1NDU1MFowgYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApO NTBaGA8yMDUzMDQxMDE1NDU1MFowgYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApO
ZXcgSmVyc2V5MREwDwYDVQQHDAhTb21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1 ZXcgSmVyc2V5MREwDwYDVQQHDAhTb21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1
cmUxEDAOBgNVBAsMB0FyY3VsdXMxITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8t cmUxEDAOBgNVBAsMB0FyY3VsdXMxITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8t
Q0EtUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCgG7r6VA/h+BynUnyDZ Q0EtUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCgG7r6VA/h+BynUnyDZ
MD0VZkYW6RGnph0w25gQDWMoqAaiUaFG5MClkhakIBpLF+6xJBhO1gs+7C1k/juV MD0VZkYW6RGnph0w25gQDWMoqAaiUaFG5MClkhakIBpLF+6xJBhO1gs+7C1k/juV
uv2jgfMwgfAwHQYDVR0OBBYEFJz1gFtTTBNfffDKvdjpUEyp70ztMIHABgNVHSME uv2jgfMwgfAwHQYDVR0OBBYEFJz1gFtTTBNfffDKvdjpUEyp70ztMIHABgNVHSME
gbgwgbWAFJz1gFtTTBNfffDKvdjpUEyp70ztoYGGpIGDMIGAMQswCQYDVQQGEwJV gbgwgbWAFJz1gFtTTBNfffDKvdjpUEyp70ztoYGGpIGDMIGAMQswCQYDVQQGEwJV
UzETMBEGA1UECAwKTmV3IEplcnNleTERMA8GA1UEBwwIU29tZXJzZXQxFDASBgNV UzETMBEGA1UECAwKTmV3IEplcnNleTERMA8GA1UEBwwIU29tZXJzZXQxFDASBgNV
BAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQLDAdBcmN1bHVzMSEwHwYDVQQDDBhDb21w BAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQLDAdBcmN1bHVzMSEwHwYDVQQDDBhDb21w
b1NlY3VyZS1GSURPLUNBLVJvb3SCFE1yctvJaUFZYSKexEwYvlOG3Gg/MAwGA1Ud b1NlY3VyZS1GSURPLUNBLVJvb3SCFE1yctvJaUFZYSKexEwYvlOG3Gg/MAwGA1Ud
EwQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgcgXGMDP2rfh4ETY9EJLwuXo1S9Ui EwQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgcgXGMDP2rfh4ETY9EJLwuXo1S9Ui
qtEmPhq9/diS0nACIQDoyLZosx8rRAF1vpRXcsVQDDSHoEs/PbmF3Er/mJ0x6w== qtEmPhq9/diS0nACIQDoyLZosx8rRAF1vpRXcsVQDDSHoEs/PbmF3Er/mJ0x6w==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,21 +1,21 @@
Arculus FIDO 2.1 Key Card Arculus FIDO 2.1 Key Card
------------------------- -------------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIC5DCCAoqgAwIBAgIJAJ1mgX+TKiH7MAoGCCqGSM49BAMCMIGAMQswCQYDVQQG MIIC5DCCAoqgAwIBAgIJAJ1mgX+TKiH7MAoGCCqGSM49BAMCMIGAMQswCQYDVQQG
EwJVUzETMBEGA1UECAwKTmV3IEplcnNleTERMA8GA1UEBwwIU29tZXJzZXQxFDAS EwJVUzETMBEGA1UECAwKTmV3IEplcnNleTERMA8GA1UEBwwIU29tZXJzZXQxFDAS
BgNVBAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQLDAdBcmN1bHVzMSEwHwYDVQQDDBhD BgNVBAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQLDAdBcmN1bHVzMSEwHwYDVQQDDBhD
b21wb1NlY3VyZS1GSURPLUNBLVJvb3QwIBcNMjMwMTEzMTc1NTMwWhgPMjA1MzAx b21wb1NlY3VyZS1GSURPLUNBLVJvb3QwIBcNMjMwMTEzMTc1NTMwWhgPMjA1MzAx
MDUxNzU1MzBaMIGAMQswCQYDVQQGEwJVUzETMBEGA1UECAwKTmV3IEplcnNleTER MDUxNzU1MzBaMIGAMQswCQYDVQQGEwJVUzETMBEGA1UECAwKTmV3IEplcnNleTER
MA8GA1UEBwwIU29tZXJzZXQxFDASBgNVBAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQL MA8GA1UEBwwIU29tZXJzZXQxFDASBgNVBAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQL
DAdBcmN1bHVzMSEwHwYDVQQDDBhDb21wb1NlY3VyZS1GSURPLUNBLVJvb3QwWTAT DAdBcmN1bHVzMSEwHwYDVQQDDBhDb21wb1NlY3VyZS1GSURPLUNBLVJvb3QwWTAT
BgcqhkjOPQIBBggqhkjOPQMBBwNCAAR3NlslpEpX/BiZ9RpWE+qrm2IRMLi3bksd BgcqhkjOPQIBBggqhkjOPQMBBwNCAAR3NlslpEpX/BiZ9RpWE+qrm2IRMLi3bksd
aHSpA8+ozUaFavT4L0pPSLBhnTRF15CaTHJMcEUGugr/xoGTdLNpo4HoMIHlMB0G aHSpA8+ozUaFavT4L0pPSLBhnTRF15CaTHJMcEUGugr/xoGTdLNpo4HoMIHlMB0G
A1UdDgQWBBR4z78sTmaiwHBw0fzV66W6fl/9WDCBtQYDVR0jBIGtMIGqgBR4z78s A1UdDgQWBBR4z78sTmaiwHBw0fzV66W6fl/9WDCBtQYDVR0jBIGtMIGqgBR4z78s
TmaiwHBw0fzV66W6fl/9WKGBhqSBgzCBgDELMAkGA1UEBhMCVVMxEzARBgNVBAgM TmaiwHBw0fzV66W6fl/9WKGBhqSBgzCBgDELMAkGA1UEBhMCVVMxEzARBgNVBAgM
Ck5ldyBKZXJzZXkxETAPBgNVBAcMCFNvbWVyc2V0MRQwEgYDVQQKDAtDb21wb1Nl Ck5ldyBKZXJzZXkxETAPBgNVBAcMCFNvbWVyc2V0MRQwEgYDVQQKDAtDb21wb1Nl
Y3VyZTEQMA4GA1UECwwHQXJjdWx1czEhMB8GA1UEAwwYQ29tcG9TZWN1cmUtRklE Y3VyZTEQMA4GA1UECwwHQXJjdWx1czEhMB8GA1UEAwwYQ29tcG9TZWN1cmUtRklE
Ty1DQS1Sb290ggkAnWaBf5MqIfswDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQDAgNI Ty1DQS1Sb290ggkAnWaBf5MqIfswDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQDAgNI
ADBFAiBpeKFNvzFvn+zY8cQdmFGrtl01Jxyllavlqxutc2xtRgIhAO01eFsUvTDd ADBFAiBpeKFNvzFvn+zY8cQdmFGrtl01Jxyllavlqxutc2xtRgIhAO01eFsUvTDd
kTeHm9eAvwLP5vXNIrU3MOxjwaIltaOY kTeHm9eAvwLP5vXNIrU3MOxjwaIltaOY
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,21 +1,21 @@
Arculus FIDO 2.1 Key Card [P71] Arculus FIDO 2.1 Key Card [P71]
------------------------------- -------------------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIC+jCCAqCgAwIBAgIUTXJy28lpQVlhIp7ETBi+U4bcaD8wCgYIKoZIzj0EAwIw MIIC+jCCAqCgAwIBAgIUTXJy28lpQVlhIp7ETBi+U4bcaD8wCgYIKoZIzj0EAwIw
gYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApOZXcgSmVyc2V5MREwDwYDVQQHDAhT gYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApOZXcgSmVyc2V5MREwDwYDVQQHDAhT
b21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1cmUxEDAOBgNVBAsMB0FyY3VsdXMx b21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1cmUxEDAOBgNVBAsMB0FyY3VsdXMx
ITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8tQ0EtUm9vdDAgFw0yMzA0MTgxNTQ1 ITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8tQ0EtUm9vdDAgFw0yMzA0MTgxNTQ1
NTBaGA8yMDUzMDQxMDE1NDU1MFowgYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApO NTBaGA8yMDUzMDQxMDE1NDU1MFowgYAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApO
ZXcgSmVyc2V5MREwDwYDVQQHDAhTb21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1 ZXcgSmVyc2V5MREwDwYDVQQHDAhTb21lcnNldDEUMBIGA1UECgwLQ29tcG9TZWN1
cmUxEDAOBgNVBAsMB0FyY3VsdXMxITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8t cmUxEDAOBgNVBAsMB0FyY3VsdXMxITAfBgNVBAMMGENvbXBvU2VjdXJlLUZJRE8t
Q0EtUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCgG7r6VA/h+BynUnyDZ Q0EtUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCgG7r6VA/h+BynUnyDZ
MD0VZkYW6RGnph0w25gQDWMoqAaiUaFG5MClkhakIBpLF+6xJBhO1gs+7C1k/juV MD0VZkYW6RGnph0w25gQDWMoqAaiUaFG5MClkhakIBpLF+6xJBhO1gs+7C1k/juV
uv2jgfMwgfAwHQYDVR0OBBYEFJz1gFtTTBNfffDKvdjpUEyp70ztMIHABgNVHSME uv2jgfMwgfAwHQYDVR0OBBYEFJz1gFtTTBNfffDKvdjpUEyp70ztMIHABgNVHSME
gbgwgbWAFJz1gFtTTBNfffDKvdjpUEyp70ztoYGGpIGDMIGAMQswCQYDVQQGEwJV gbgwgbWAFJz1gFtTTBNfffDKvdjpUEyp70ztoYGGpIGDMIGAMQswCQYDVQQGEwJV
UzETMBEGA1UECAwKTmV3IEplcnNleTERMA8GA1UEBwwIU29tZXJzZXQxFDASBgNV UzETMBEGA1UECAwKTmV3IEplcnNleTERMA8GA1UEBwwIU29tZXJzZXQxFDASBgNV
BAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQLDAdBcmN1bHVzMSEwHwYDVQQDDBhDb21w BAoMC0NvbXBvU2VjdXJlMRAwDgYDVQQLDAdBcmN1bHVzMSEwHwYDVQQDDBhDb21w
b1NlY3VyZS1GSURPLUNBLVJvb3SCFE1yctvJaUFZYSKexEwYvlOG3Gg/MAwGA1Ud b1NlY3VyZS1GSURPLUNBLVJvb3SCFE1yctvJaUFZYSKexEwYvlOG3Gg/MAwGA1Ud
EwQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgcgXGMDP2rfh4ETY9EJLwuXo1S9Ui EwQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgcgXGMDP2rfh4ETY9EJLwuXo1S9Ui
qtEmPhq9/diS0nACIQDoyLZosx8rRAF1vpRXcsVQDDSHoEs/PbmF3Er/mJ0x6w== qtEmPhq9/diS0nACIQDoyLZosx8rRAF1vpRXcsVQDDSHoEs/PbmF3Er/mJ0x6w==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,15 +1,15 @@
ATKey.Card CTAP2.0 ATKey.Card CTAP2.0
------------------ ------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIBzDCCAXGgAwIBAgIBATAKBggqhkjOPQQDAjBiMQswCQYDVQQGEwJTRTESMBAG MIIBzDCCAXGgAwIBAgIBATAKBggqhkjOPQQDAjBiMQswCQYDVQQGEwJTRTESMBAG
A1UECgwJQVRLZXlDQTAwMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0 A1UECgwJQVRLZXlDQTAwMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0
aW9uMRswGQYDVQQDExJBdXRoZW50cmVuZCBDQSAwMDAwIBcNMTYwMjI2MDgxMTA2 aW9uMRswGQYDVQQDExJBdXRoZW50cmVuZCBDQSAwMDAwIBcNMTYwMjI2MDgxMTA2
WhgPMjA1MDAyMjUwODExMDZaMGIxCzAJBgNVBAYTAlNFMRIwEAYDVQQKDAlBVEtl WhgPMjA1MDAyMjUwODExMDZaMGIxCzAJBgNVBAYTAlNFMRIwEAYDVQQKDAlBVEtl
eUNBMDAxIjAgBgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xGzAZBgNV eUNBMDAxIjAgBgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xGzAZBgNV
BAMTEkF1dGhlbnRyZW5kIENBIDAwMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA BAMTEkF1dGhlbnRyZW5kIENBIDAwMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
BAJcWqeCxga9KJbFO2TZdjcgrtZAgfi8TXKu+v5lcR5ceb5GJYxyoCjhueESL3dd BAJcWqeCxga9KJbFO2TZdjcgrtZAgfi8TXKu+v5lcR5ceb5GJYxyoCjhueESL3dd
mMIkpGyhsEEtfFUyBwsyFVCjFjAUMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZI mMIkpGyhsEEtfFUyBwsyFVCjFjAUMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZI
zj0EAwIDSQAwRgIhAL4TbP00sENbTEXGoagM6Hkl2XIDrxgKbHwow/9GibYTAiEA zj0EAwIDSQAwRgIhAL4TbP00sENbTEXGoagM6Hkl2XIDrxgKbHwow/9GibYTAiEA
udIm7EGqfya8QygKcbkQfqrwefYnBvZKI0xwn/kKWx4= udIm7EGqfya8QygKcbkQfqrwefYnBvZKI0xwn/kKWx4=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,13 +1,13 @@
ATKey.Card NFC ATKey.Card NFC
-------------- --------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIBbTCCARSgAwIBAgIBATAKBggqhkjOPQQDAjAtMSswKQYDVQQDDCJBdXRoZW50 MIIBbTCCARSgAwIBAgIBATAKBggqhkjOPQQDAjAtMSswKQYDVQQDDCJBdXRoZW50
cmVuZCBBVEtleSBSb290IENBIDIwMjIwOTA4MCAXDTIyMDkwODA4Mzg1N1oYDzIw cmVuZCBBVEtleSBSb290IENBIDIwMjIwOTA4MCAXDTIyMDkwODA4Mzg1N1oYDzIw
NjIwODI5MDgzODU3WjAtMSswKQYDVQQDDCJBdXRoZW50cmVuZCBBVEtleSBSb290 NjIwODI5MDgzODU3WjAtMSswKQYDVQQDDCJBdXRoZW50cmVuZCBBVEtleSBSb290
IENBIDIwMjIwOTA4MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/N+v/Pbx64tD IENBIDIwMjIwOTA4MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/N+v/Pbx64tD
vMMiSkcjwP5M8D2IUfrGl0HnzoHMJGUwb+R48MezWi1J3ZBXeOpSHfjrgxFfo3ir vMMiSkcjwP5M8D2IUfrGl0HnzoHMJGUwb+R48MezWi1J3ZBXeOpSHfjrgxFfo3ir
LeLVwIK7C6MjMCEwDwYDVR0TBAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwCgYI LeLVwIK7C6MjMCEwDwYDVR0TBAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwCgYI
KoZIzj0EAwIDRwAwRAIgWqn3eN+y0V933MGj3fQrdrUXs8VmUprEs7C0NV98DTIC KoZIzj0EAwIDRwAwRAIgWqn3eN+y0V933MGj3fQrdrUXs8VmUprEs7C0NV98DTIC
IEYC++9dO4cjaURuW4bdtOzIq0P4cTWd7pScBajLN3dx IEYC++9dO4cjaURuW4bdtOzIq0P4cTWd7pScBajLN3dx
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,12 +1,12 @@
ATKey.Hello TypeC ATKey.Hello TypeC
----------------- -----------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIBSTCB76ADAgECAhDyFMXqOf/nEYeDgG5vbmljMAoGCCqGSM49BAMCMCgxJjAk MIIBSTCB76ADAgECAhDyFMXqOf/nEYeDgG5vbmljMAoGCCqGSM49BAMCMCgxJjAk
BgNVBAMTHUVnaXNUZWMgRmluZ2VycHJpbnQgVTJGIFZEIENBMB4XDTE4MDEyMzAw BgNVBAMTHUVnaXNUZWMgRmluZ2VycHJpbnQgVTJGIFZEIENBMB4XDTE4MDEyMzAw
MDAwMFoXDTIzMDEyMzA1NTk1OVowJTEjMCEGA1UEAxMaRWdpc1RlYyBGaW5nZXJw MDAwMFoXDTIzMDEyMzA1NTk1OVowJTEjMCEGA1UEAxMaRWdpc1RlYyBGaW5nZXJw
cmludCBVMkYgVkQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASj6/E9C4cTFsEH cmludCBVMkYgVkQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASj6/E9C4cTFsEH
vOJGEVvkDgHRwJWQr4uCtVcbKsFUKm9luL6aRR52FRGTIdzbjUMk1ieDyRHu7KKW vOJGEVvkDgHRwJWQr4uCtVcbKsFUKm9luL6aRR52FRGTIdzbjUMk1ieDyRHu7KKW
RNF14M+NMAoGCCqGSM49BAMCA0kAMEYCIQCQhjolqZveADb0w7vds8+1pFy3WBUi RNF14M+NMAoGCCqGSM49BAMCA0kAMEYCIQCQhjolqZveADb0w7vds8+1pFy3WBUi
JsDLvkWD6uP/qQIhAKKHu4LaiZDqtRTq9/aFK4L4oSpaQVG7hzvZcVP2YWyJ JsDLvkWD6uP/qQIhAKKHu4LaiZDqtRTq9/aFK4L4oSpaQVG7hzvZcVP2YWyJ
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,15 +1,15 @@
ATKey.Pro CTAP2.0 ATKey.Pro CTAP2.0
----------------- -----------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIBzDCCAXGgAwIBAgIBATAKBggqhkjOPQQDAjBiMQswCQYDVQQGEwJTRTESMBAG MIIBzDCCAXGgAwIBAgIBATAKBggqhkjOPQQDAjBiMQswCQYDVQQGEwJTRTESMBAG
A1UECgwJQVRLZXlDQTAwMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0 A1UECgwJQVRLZXlDQTAwMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0
aW9uMRswGQYDVQQDExJBdXRoZW50cmVuZCBDQSAwMDAwIBcNMTYwMjI2MDgxMTA2 aW9uMRswGQYDVQQDExJBdXRoZW50cmVuZCBDQSAwMDAwIBcNMTYwMjI2MDgxMTA2
WhgPMjA1MDAyMjUwODExMDZaMGIxCzAJBgNVBAYTAlNFMRIwEAYDVQQKDAlBVEtl WhgPMjA1MDAyMjUwODExMDZaMGIxCzAJBgNVBAYTAlNFMRIwEAYDVQQKDAlBVEtl
eUNBMDAxIjAgBgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xGzAZBgNV eUNBMDAxIjAgBgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xGzAZBgNV
BAMTEkF1dGhlbnRyZW5kIENBIDAwMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA BAMTEkF1dGhlbnRyZW5kIENBIDAwMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
BAJcWqeCxga9KJbFO2TZdjcgrtZAgfi8TXKu+v5lcR5ceb5GJYxyoCjhueESL3dd BAJcWqeCxga9KJbFO2TZdjcgrtZAgfi8TXKu+v5lcR5ceb5GJYxyoCjhueESL3dd
mMIkpGyhsEEtfFUyBwsyFVCjFjAUMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZI mMIkpGyhsEEtfFUyBwsyFVCjFjAUMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZI
zj0EAwIDSQAwRgIhAL4TbP00sENbTEXGoagM6Hkl2XIDrxgKbHwow/9GibYTAiEA zj0EAwIDSQAwRgIhAL4TbP00sENbTEXGoagM6Hkl2XIDrxgKbHwow/9GibYTAiEA
udIm7EGqfya8QygKcbkQfqrwefYnBvZKI0xwn/kKWx4= udIm7EGqfya8QygKcbkQfqrwefYnBvZKI0xwn/kKWx4=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,15 +1,15 @@
ATKey.Pro CTAP2.1 ATKey.Pro CTAP2.1
----------------- -----------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIBzDCCAXGgAwIBAgIBATAKBggqhkjOPQQDAjBiMQswCQYDVQQGEwJTRTESMBAG MIIBzDCCAXGgAwIBAgIBATAKBggqhkjOPQQDAjBiMQswCQYDVQQGEwJTRTESMBAG
A1UECgwJQVRLZXlDQTAwMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0 A1UECgwJQVRLZXlDQTAwMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0
aW9uMRswGQYDVQQDExJBdXRoZW50cmVuZCBDQSAwMDAwIBcNMTYwMjI2MDgxMTA2 aW9uMRswGQYDVQQDExJBdXRoZW50cmVuZCBDQSAwMDAwIBcNMTYwMjI2MDgxMTA2
WhgPMjA1MDAyMjUwODExMDZaMGIxCzAJBgNVBAYTAlNFMRIwEAYDVQQKDAlBVEtl WhgPMjA1MDAyMjUwODExMDZaMGIxCzAJBgNVBAYTAlNFMRIwEAYDVQQKDAlBVEtl
eUNBMDAxIjAgBgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xGzAZBgNV eUNBMDAxIjAgBgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xGzAZBgNV
BAMTEkF1dGhlbnRyZW5kIENBIDAwMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA BAMTEkF1dGhlbnRyZW5kIENBIDAwMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
BAJcWqeCxga9KJbFO2TZdjcgrtZAgfi8TXKu+v5lcR5ceb5GJYxyoCjhueESL3dd BAJcWqeCxga9KJbFO2TZdjcgrtZAgfi8TXKu+v5lcR5ceb5GJYxyoCjhueESL3dd
mMIkpGyhsEEtfFUyBwsyFVCjFjAUMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZI mMIkpGyhsEEtfFUyBwsyFVCjFjAUMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZI
zj0EAwIDSQAwRgIhAL4TbP00sENbTEXGoagM6Hkl2XIDrxgKbHwow/9GibYTAiEA zj0EAwIDSQAwRgIhAL4TbP00sENbTEXGoagM6Hkl2XIDrxgKbHwow/9GibYTAiEA
udIm7EGqfya8QygKcbkQfqrwefYnBvZKI0xwn/kKWx4= udIm7EGqfya8QygKcbkQfqrwefYnBvZKI0xwn/kKWx4=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,13 +1,13 @@
ATKey.ProS ATKey.ProS
---------- ----------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIBbTCCARSgAwIBAgIBATAKBggqhkjOPQQDAjAtMSswKQYDVQQDDCJBdXRoZW50 MIIBbTCCARSgAwIBAgIBATAKBggqhkjOPQQDAjAtMSswKQYDVQQDDCJBdXRoZW50
cmVuZCBBVEtleSBSb290IENBIDIwMjIwOTA4MCAXDTIyMDkwODA4Mzg1N1oYDzIw cmVuZCBBVEtleSBSb290IENBIDIwMjIwOTA4MCAXDTIyMDkwODA4Mzg1N1oYDzIw
NjIwODI5MDgzODU3WjAtMSswKQYDVQQDDCJBdXRoZW50cmVuZCBBVEtleSBSb290 NjIwODI5MDgzODU3WjAtMSswKQYDVQQDDCJBdXRoZW50cmVuZCBBVEtleSBSb290
IENBIDIwMjIwOTA4MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/N+v/Pbx64tD IENBIDIwMjIwOTA4MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/N+v/Pbx64tD
vMMiSkcjwP5M8D2IUfrGl0HnzoHMJGUwb+R48MezWi1J3ZBXeOpSHfjrgxFfo3ir vMMiSkcjwP5M8D2IUfrGl0HnzoHMJGUwb+R48MezWi1J3ZBXeOpSHfjrgxFfo3ir
LeLVwIK7C6MjMCEwDwYDVR0TBAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwCgYI LeLVwIK7C6MjMCEwDwYDVR0TBAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwCgYI
KoZIzj0EAwIDRwAwRAIgWqn3eN+y0V933MGj3fQrdrUXs8VmUprEs7C0NV98DTIC KoZIzj0EAwIDRwAwRAIgWqn3eN+y0V933MGj3fQrdrUXs8VmUprEs7C0NV98DTIC
IEYC++9dO4cjaURuW4bdtOzIq0P4cTWd7pScBajLN3dx IEYC++9dO4cjaURuW4bdtOzIq0P4cTWd7pScBajLN3dx
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,14 +1,14 @@
ATLKey Authenticator ATLKey Authenticator
-------------------- --------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIBnTCCAUSgAwIBAgIUeCtNNwTi+UmLgnuS00DCjxZ0aFQwCgYIKoZIzj0EAwIw MIIBnTCCAUSgAwIBAgIUeCtNNwTi+UmLgnuS00DCjxZ0aFQwCgYIKoZIzj0EAwIw
PTEaMBgGA1UEAwwRQXRsYW5jdWJlIEZJRE8gQ0ExEjAQBgNVBAoMCUF0bGFuY3Vi PTEaMBgGA1UEAwwRQXRsYW5jdWJlIEZJRE8gQ0ExEjAQBgNVBAoMCUF0bGFuY3Vi
ZTELMAkGA1UEBhMCVFcwIBcNMjUwNjE5MTUxOTIzWhgPMjEyNDA1MjcxNTE5MjNa ZTELMAkGA1UEBhMCVFcwIBcNMjUwNjE5MTUxOTIzWhgPMjEyNDA1MjcxNTE5MjNa
MD0xGjAYBgNVBAMMEUF0bGFuY3ViZSBGSURPIENBMRIwEAYDVQQKDAlBdGxhbmN1 MD0xGjAYBgNVBAMMEUF0bGFuY3ViZSBGSURPIENBMRIwEAYDVQQKDAlBdGxhbmN1
YmUxCzAJBgNVBAYTAlRXMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEERKz3/zP YmUxCzAJBgNVBAYTAlRXMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEERKz3/zP
n9Pn7zZGPyacSbjY0CALdPHPHED2w3Wc+mU+K7poYWzvjuI9M3Pya9iJrJ00ltDA n9Pn7zZGPyacSbjY0CALdPHPHED2w3Wc+mU+K7poYWzvjuI9M3Pya9iJrJ00ltDA
0/VZW28lra+w4aMgMB4wDwYDVR0TBAgwBgEB/wIBADALBgNVHQ8EBAMCAQYwCgYI 0/VZW28lra+w4aMgMB4wDwYDVR0TBAgwBgEB/wIBADALBgNVHQ8EBAMCAQYwCgYI
KoZIzj0EAwIDRwAwRAIgLZvGZGlepxiFBbU8WdknXucloW6sHNo0YKDMC7cQuG4C KoZIzj0EAwIDRwAwRAIgLZvGZGlepxiFBbU8WdknXucloW6sHNo0YKDMC7cQuG4C
ID/q7aLWkprtHyZJEasve1Pk796Qa1GohXOXHXMDCRXu ID/q7aLWkprtHyZJEasve1Pk796Qa1GohXOXHXMDCRXu
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,27 +1,27 @@
Atos CardOS FIDO2 Atos CardOS FIDO2
----------------- -----------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIBnTCCAUOgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMFQxCzAJBgNVBAYT MIIBnTCCAUOgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMFQxCzAJBgNVBAYT
AkdFMQ0wCwYDVQQKDARBdG9zMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVz AkdFMQ0wCwYDVQQKDARBdG9zMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVz
dGF0aW9uMRIwEAYDVQQDDAlBdG9zIHJvb3QwHhcNMjIwMzA4MTEyMDI5WhcNMzcw dGF0aW9uMRIwEAYDVQQDDAlBdG9zIHJvb3QwHhcNMjIwMzA4MTEyMDI5WhcNMzcw
MzA0MTEyMDI5WjBUMQswCQYDVQQGEwJHRTENMAsGA1UECgwEQXRvczEiMCAGA1UE MzA0MTEyMDI5WjBUMQswCQYDVQQGEwJHRTENMAsGA1UECgwEQXRvczEiMCAGA1UE
CwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjESMBAGA1UEAwwJQXRvcyByb290 CwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjESMBAGA1UEAwwJQXRvcyByb290
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj28UDEcSqGRUT1PMDasmj2Gd6BsT MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj28UDEcSqGRUT1PMDasmj2Gd6BsT
TS0M1O2W9dM0YEY9hrDgD/AswRVcRbxnyt3xdCP0KhIiegNIRwUcVEJvezAKBggq TS0M1O2W9dM0YEY9hrDgD/AswRVcRbxnyt3xdCP0KhIiegNIRwUcVEJvezAKBggq
hkjOPQQDAgNIADBFAiEA61mCCoCnDxCkVBXDmhjmG01ibdRWV63j5ScSjBFnIkcC hkjOPQQDAgNIADBFAiEA61mCCoCnDxCkVBXDmhjmG01ibdRWV63j5ScSjBFnIkcC
IEAd1Wwb1iUyKBfjpxk/R/t0OsptPOIF87uShy3lXvbH IEAd1Wwb1iUyKBfjpxk/R/t0OsptPOIF87uShy3lXvbH
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIBsjCCAVigAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMFQxCzAJBgNVBAYT MIIBsjCCAVigAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMFQxCzAJBgNVBAYT
AkdFMQ0wCwYDVQQKDARBdG9zMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVz AkdFMQ0wCwYDVQQKDARBdG9zMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVz
dGF0aW9uMRIwEAYDVQQDDAlBdG9zIHJvb3QwHhcNMjAwOTA5MDYxNDU4WhcNMzAw dGF0aW9uMRIwEAYDVQQDDAlBdG9zIHJvb3QwHhcNMjAwOTA5MDYxNDU4WhcNMzAw
OTA3MDYxNDU4WjBUMQswCQYDVQQGEwJHRTENMAsGA1UECgwEQXRvczEiMCAGA1UE OTA3MDYxNDU4WjBUMQswCQYDVQQGEwJHRTENMAsGA1UECgwEQXRvczEiMCAGA1UE
CwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjESMBAGA1UEAwwJQXRvcyByb290 CwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjESMBAGA1UEAwwJQXRvcyByb290
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpKR0f6Vdq0PYXxH7JVMkGxNoM4Xo MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpKR0f6Vdq0PYXxH7JVMkGxNoM4Xo
HFuQ+e7qf+04P4J2GGS9vXFLVQZ5coFnRPfCflDCLkzafM3QEdcYCVoyPKMTMBEw HFuQ+e7qf+04P4J2GGS9vXFLVQZ5coFnRPfCflDCLkzafM3QEdcYCVoyPKMTMBEw
DwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAzXpow3/4yOXNbALo DwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAzXpow3/4yOXNbALo
dMv5KIornn5wRRI36YQpv3Wbh00CIEy14Sy7LrlgJSZTG0Md5wjQbyoVTfU/2oZy dMv5KIornn5wRRI36YQpv3Wbh00CIEy14Sy7LrlgJSZTG0Md5wjQbyoVTfU/2oZy
p9EnplDL p9EnplDL
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,57 +1,57 @@
authenton1 - CTAP2.1 authenton1 - CTAP2.1
-------------------- --------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
WD9f WD9f
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIFhDCCBGygAwIBAgIMbUI9+zyEQUTD+dnCMA0GCSqGSIb3DQEBCwUAMFsxCzAJ MIIFhDCCBGygAwIBAgIMbUI9+zyEQUTD+dnCMA0GCSqGSIb3DQEBCwUAMFsxCzAJ
BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTEwLwYDVQQDEyhH BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTEwLwYDVQQDEyhH
bG9iYWxTaWduIEdDQyBSMyBQZXJzb25hbFNpZ24gMiBDQSAyMDIwMB4XDTIzMDEy bG9iYWxTaWduIEdDQyBSMyBQZXJzb25hbFNpZ24gMiBDQSAyMDIwMB4XDTIzMDEy
NDE1MDEwM1oXDTI2MDEyNDE1MDEwM1owgbYxCzAJBgNVBAYTAkRFMQ8wDQYDVQQI NDE1MDEwM1oXDTI2MDEyNDE1MDEwM1owgbYxCzAJBgNVBAYTAkRFMQ8wDQYDVQQI
EwZCYXllcm4xETAPBgNVBAcTCEFzY2hoZWltMSowKAYDVQQKEyFBSVhlY3V0aXZl EwZCYXllcm4xETAPBgNVBAcTCEFzY2hoZWltMSowKAYDVQQKEyFBSVhlY3V0aXZl
LmNvbSAoQXhlbCBWb25kZXJoYWdlbikxEjAQBgNVBAsTCWF1dGhlbnRvbjETMBEG LmNvbSAoQXhlbCBWb25kZXJoYWdlbikxEjAQBgNVBAsTCWF1dGhlbnRvbjETMBEG
A1UEAxMKQUlYZWN1dGl2ZTEuMCwGCSqGSIb3DQEJARYfQVhFTC5WT05ERVJIQUdF A1UEAxMKQUlYZWN1dGl2ZTEuMCwGCSqGSIb3DQEJARYfQVhFTC5WT05ERVJIQUdF
TkBBSVhFQ1VUSVZFLkNPTTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB TkBBSVhFQ1VUSVZFLkNPTTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AKf/4GzGAUmJH4R9mCvcJ+CgTUgP1DNr8dN2kDvSA9xuIMb1NZJXQgxSOOAYqIBz AKf/4GzGAUmJH4R9mCvcJ+CgTUgP1DNr8dN2kDvSA9xuIMb1NZJXQgxSOOAYqIBz
FNcjkNVl80Y3drm4tPJSl3kfWWM26xYLFsvl1BcqtrPrssyxIBtX5kTe2p+M9Rlc FNcjkNVl80Y3drm4tPJSl3kfWWM26xYLFsvl1BcqtrPrssyxIBtX5kTe2p+M9Rlc
ZQcEj5CbYpASpuSTByzoOuf+VSfOUVqDzCDH4CqsECyvyLKrJw9kjN4B6lFXyzmr ZQcEj5CbYpASpuSTByzoOuf+VSfOUVqDzCDH4CqsECyvyLKrJw9kjN4B6lFXyzmr
IWqRmGWKx4cso/wxYIUNcOV+p6I84Y2z1nFIWEhcA6dgrJQnDpD5IGEJdSxTn8t2 IWqRmGWKx4cso/wxYIUNcOV+p6I84Y2z1nFIWEhcA6dgrJQnDpD5IGEJdSxTn8t2
ZnANp4JEAp8j5w3tbU89RKi3yPAuwsxi3XcloFAtGxw2wk7nJyizq98tO5lwfgHN ZnANp4JEAp8j5w3tbU89RKi3yPAuwsxi3XcloFAtGxw2wk7nJyizq98tO5lwfgHN
/YnglYwU4UFnOBzP5MuzPrECAwEAAaOCAeowggHmMA4GA1UdDwEB/wQEAwIFoDCB /YnglYwU4UFnOBzP5MuzPrECAwEAAaOCAeowggHmMA4GA1UdDwEB/wQEAwIFoDCB
owYIKwYBBQUHAQEEgZYwgZMwTgYIKwYBBQUHMAKGQmh0dHA6Ly9zZWN1cmUuZ2xv owYIKwYBBQUHAQEEgZYwgZMwTgYIKwYBBQUHMAKGQmh0dHA6Ly9zZWN1cmUuZ2xv
YmFsc2lnbi5jb20vY2FjZXJ0L2dzZ2NjcjNwZXJzb25hbHNpZ24yY2EyMDIwLmNy YmFsc2lnbi5jb20vY2FjZXJ0L2dzZ2NjcjNwZXJzb25hbHNpZ24yY2EyMDIwLmNy
dDBBBggrBgEFBQcwAYY1aHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vZ3NnY2Ny dDBBBggrBgEFBQcwAYY1aHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vZ3NnY2Ny
M3BlcnNvbmFsc2lnbjJjYTIwMjAwTQYDVR0gBEYwRDBCBgorBgEEAaAyASgKMDQw M3BlcnNvbmFsc2lnbjJjYTIwMjAwTQYDVR0gBEYwRDBCBgorBgEEAaAyASgKMDQw
MgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRv MgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRv
cnkvMAkGA1UdEwQCMAAwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2NybC5nbG9i cnkvMAkGA1UdEwQCMAAwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2NybC5nbG9i
YWxzaWduLmNvbS9nc2djY3IzcGVyc29uYWxzaWduMmNhMjAyMC5jcmwwKgYDVR0R YWxzaWduLmNvbS9nc2djY3IzcGVyc29uYWxzaWduMmNhMjAyMC5jcmwwKgYDVR0R
BCMwIYEfQVhFTC5WT05ERVJIQUdFTkBBSVhFQ1VUSVZFLkNPTTAdBgNVHSUEFjAU BCMwIYEfQVhFTC5WT05ERVJIQUdFTkBBSVhFQ1VUSVZFLkNPTTAdBgNVHSUEFjAU
BggrBgEFBQcDAgYIKwYBBQUHAwQwHwYDVR0jBBgwFoAUljPR5lgXWzR1ioFWZNW+ BggrBgEFBQcDAgYIKwYBBQUHAwQwHwYDVR0jBBgwFoAUljPR5lgXWzR1ioFWZNW+
SN6hj88wHQYDVR0OBBYEFC57LN3RW38dexQhxfHW/WWt7cCQMA0GCSqGSIb3DQEB SN6hj88wHQYDVR0OBBYEFC57LN3RW38dexQhxfHW/WWt7cCQMA0GCSqGSIb3DQEB
CwUAA4IBAQCvvPim7joF0G4vOepSFbCRgtCwRAyen9fHzDS27WnsTbG9Uoq+ziGr CwUAA4IBAQCvvPim7joF0G4vOepSFbCRgtCwRAyen9fHzDS27WnsTbG9Uoq+ziGr
cD+U5EnH6UrmF1BqxXL1CjqEPrn5YQtZSs3pfvonXkFChtiYYOgK4gIqJtCVBaX3 cD+U5EnH6UrmF1BqxXL1CjqEPrn5YQtZSs3pfvonXkFChtiYYOgK4gIqJtCVBaX3
H4DHkI1V7Bh7b4vjZAD8cJLxiJf6AvI4e11D9K5tpZ7YZQE5Mw49VDtQ8A7pkjO6 H4DHkI1V7Bh7b4vjZAD8cJLxiJf6AvI4e11D9K5tpZ7YZQE5Mw49VDtQ8A7pkjO6
wXjHFXXgY1lPw+LRQuU3m9KGAM3C4ge0otpW0XyKDxqsKWOxmMX7IjhXFDpKYopm wXjHFXXgY1lPw+LRQuU3m9KGAM3C4ge0otpW0XyKDxqsKWOxmMX7IjhXFDpKYopm
mLPcTz70ONtbE2NHyIa3UujhcjbcrpoNkmaFiLk2pqKRZIoHkZaFMd9waQ9f1lS2 mLPcTz70ONtbE2NHyIa3UujhcjbcrpoNkmaFiLk2pqKRZIoHkZaFMd9waQ9f1lS2
wwVQxtH+vNV9N3K+HnL3nB/CU2E0btJH wwVQxtH+vNV9N3K+HnL3nB/CU2E0btJH
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,57 +1,57 @@
authenton1 - CTAP 2.1 authenton1 - CTAP 2.1
--------------------- ---------------------
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
WD9f WD9f
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIFhDCCBGygAwIBAgIMbUI9+zyEQUTD+dnCMA0GCSqGSIb3DQEBCwUAMFsxCzAJ MIIFhDCCBGygAwIBAgIMbUI9+zyEQUTD+dnCMA0GCSqGSIb3DQEBCwUAMFsxCzAJ
BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTEwLwYDVQQDEyhH BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTEwLwYDVQQDEyhH
bG9iYWxTaWduIEdDQyBSMyBQZXJzb25hbFNpZ24gMiBDQSAyMDIwMB4XDTIzMDEy bG9iYWxTaWduIEdDQyBSMyBQZXJzb25hbFNpZ24gMiBDQSAyMDIwMB4XDTIzMDEy
NDE1MDEwM1oXDTI2MDEyNDE1MDEwM1owgbYxCzAJBgNVBAYTAkRFMQ8wDQYDVQQI NDE1MDEwM1oXDTI2MDEyNDE1MDEwM1owgbYxCzAJBgNVBAYTAkRFMQ8wDQYDVQQI
EwZCYXllcm4xETAPBgNVBAcTCEFzY2hoZWltMSowKAYDVQQKEyFBSVhlY3V0aXZl EwZCYXllcm4xETAPBgNVBAcTCEFzY2hoZWltMSowKAYDVQQKEyFBSVhlY3V0aXZl
LmNvbSAoQXhlbCBWb25kZXJoYWdlbikxEjAQBgNVBAsTCWF1dGhlbnRvbjETMBEG LmNvbSAoQXhlbCBWb25kZXJoYWdlbikxEjAQBgNVBAsTCWF1dGhlbnRvbjETMBEG
A1UEAxMKQUlYZWN1dGl2ZTEuMCwGCSqGSIb3DQEJARYfQVhFTC5WT05ERVJIQUdF A1UEAxMKQUlYZWN1dGl2ZTEuMCwGCSqGSIb3DQEJARYfQVhFTC5WT05ERVJIQUdF
TkBBSVhFQ1VUSVZFLkNPTTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB TkBBSVhFQ1VUSVZFLkNPTTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AKf/4GzGAUmJH4R9mCvcJ+CgTUgP1DNr8dN2kDvSA9xuIMb1NZJXQgxSOOAYqIBz AKf/4GzGAUmJH4R9mCvcJ+CgTUgP1DNr8dN2kDvSA9xuIMb1NZJXQgxSOOAYqIBz
FNcjkNVl80Y3drm4tPJSl3kfWWM26xYLFsvl1BcqtrPrssyxIBtX5kTe2p+M9Rlc FNcjkNVl80Y3drm4tPJSl3kfWWM26xYLFsvl1BcqtrPrssyxIBtX5kTe2p+M9Rlc
ZQcEj5CbYpASpuSTByzoOuf+VSfOUVqDzCDH4CqsECyvyLKrJw9kjN4B6lFXyzmr ZQcEj5CbYpASpuSTByzoOuf+VSfOUVqDzCDH4CqsECyvyLKrJw9kjN4B6lFXyzmr
IWqRmGWKx4cso/wxYIUNcOV+p6I84Y2z1nFIWEhcA6dgrJQnDpD5IGEJdSxTn8t2 IWqRmGWKx4cso/wxYIUNcOV+p6I84Y2z1nFIWEhcA6dgrJQnDpD5IGEJdSxTn8t2
ZnANp4JEAp8j5w3tbU89RKi3yPAuwsxi3XcloFAtGxw2wk7nJyizq98tO5lwfgHN ZnANp4JEAp8j5w3tbU89RKi3yPAuwsxi3XcloFAtGxw2wk7nJyizq98tO5lwfgHN
/YnglYwU4UFnOBzP5MuzPrECAwEAAaOCAeowggHmMA4GA1UdDwEB/wQEAwIFoDCB /YnglYwU4UFnOBzP5MuzPrECAwEAAaOCAeowggHmMA4GA1UdDwEB/wQEAwIFoDCB
owYIKwYBBQUHAQEEgZYwgZMwTgYIKwYBBQUHMAKGQmh0dHA6Ly9zZWN1cmUuZ2xv owYIKwYBBQUHAQEEgZYwgZMwTgYIKwYBBQUHMAKGQmh0dHA6Ly9zZWN1cmUuZ2xv
YmFsc2lnbi5jb20vY2FjZXJ0L2dzZ2NjcjNwZXJzb25hbHNpZ24yY2EyMDIwLmNy YmFsc2lnbi5jb20vY2FjZXJ0L2dzZ2NjcjNwZXJzb25hbHNpZ24yY2EyMDIwLmNy
dDBBBggrBgEFBQcwAYY1aHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vZ3NnY2Ny dDBBBggrBgEFBQcwAYY1aHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vZ3NnY2Ny
M3BlcnNvbmFsc2lnbjJjYTIwMjAwTQYDVR0gBEYwRDBCBgorBgEEAaAyASgKMDQw M3BlcnNvbmFsc2lnbjJjYTIwMjAwTQYDVR0gBEYwRDBCBgorBgEEAaAyASgKMDQw
MgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRv MgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRv
cnkvMAkGA1UdEwQCMAAwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2NybC5nbG9i cnkvMAkGA1UdEwQCMAAwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2NybC5nbG9i
YWxzaWduLmNvbS9nc2djY3IzcGVyc29uYWxzaWduMmNhMjAyMC5jcmwwKgYDVR0R YWxzaWduLmNvbS9nc2djY3IzcGVyc29uYWxzaWduMmNhMjAyMC5jcmwwKgYDVR0R
BCMwIYEfQVhFTC5WT05ERVJIQUdFTkBBSVhFQ1VUSVZFLkNPTTAdBgNVHSUEFjAU BCMwIYEfQVhFTC5WT05ERVJIQUdFTkBBSVhFQ1VUSVZFLkNPTTAdBgNVHSUEFjAU
BggrBgEFBQcDAgYIKwYBBQUHAwQwHwYDVR0jBBgwFoAUljPR5lgXWzR1ioFWZNW+ BggrBgEFBQcDAgYIKwYBBQUHAwQwHwYDVR0jBBgwFoAUljPR5lgXWzR1ioFWZNW+
SN6hj88wHQYDVR0OBBYEFC57LN3RW38dexQhxfHW/WWt7cCQMA0GCSqGSIb3DQEB SN6hj88wHQYDVR0OBBYEFC57LN3RW38dexQhxfHW/WWt7cCQMA0GCSqGSIb3DQEB
CwUAA4IBAQCvvPim7joF0G4vOepSFbCRgtCwRAyen9fHzDS27WnsTbG9Uoq+ziGr CwUAA4IBAQCvvPim7joF0G4vOepSFbCRgtCwRAyen9fHzDS27WnsTbG9Uoq+ziGr
cD+U5EnH6UrmF1BqxXL1CjqEPrn5YQtZSs3pfvonXkFChtiYYOgK4gIqJtCVBaX3 cD+U5EnH6UrmF1BqxXL1CjqEPrn5YQtZSs3pfvonXkFChtiYYOgK4gIqJtCVBaX3
H4DHkI1V7Bh7b4vjZAD8cJLxiJf6AvI4e11D9K5tpZ7YZQE5Mw49VDtQ8A7pkjO6 H4DHkI1V7Bh7b4vjZAD8cJLxiJf6AvI4e11D9K5tpZ7YZQE5Mw49VDtQ8A7pkjO6
wXjHFXXgY1lPw+LRQuU3m9KGAM3C4ge0otpW0XyKDxqsKWOxmMX7IjhXFDpKYopm wXjHFXXgY1lPw+LRQuU3m9KGAM3C4ge0otpW0XyKDxqsKWOxmMX7IjhXFDpKYopm
mLPcTz70ONtbE2NHyIa3UujhcjbcrpoNkmaFiLk2pqKRZIoHkZaFMd9waQ9f1lS2 mLPcTz70ONtbE2NHyIa3UujhcjbcrpoNkmaFiLk2pqKRZIoHkZaFMd9waQ9f1lS2
wwVQxtH+vNV9N3K+HnL3nB/CU2E0btJH wwVQxtH+vNV9N3K+HnL3nB/CU2E0btJH
-----END CERTIFICATE----- -----END CERTIFICATE-----

Some files were not shown because too many files have changed in this diff Show More