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

View File

@ -1,16 +1,16 @@
<?php
require_once("restricted/mysql.php");
require_once("helper.php");
$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);")){
echo mysqli_error($mysql);
}
if(isLocal()){
$accessKey = strval(random_int(0,99999999));
if(!mysqli_query($mysql,"INSERT INTO addUser SET accesskey=".$accessKey.", datetime=NOW();")){
echo mysqli_error($mysql);
}
header('Location: https://nas.el-wa.org/smart?addUser='.$accessKey);
echo 'https://nas.el-wa.org/smart?addUser='.$accessKey;
}
<?php
require_once("restricted/mysql.php");
require_once("helper.php");
$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);")){
echo mysqli_error($mysql);
}
if(isLocal()){
$accessKey = strval(random_int(0,99999999));
if(!mysqli_query($mysql,"INSERT INTO addUser SET accesskey=".$accessKey.", datetime=NOW();")){
echo mysqli_error($mysql);
}
header('Location: https://nas.el-wa.org/smart?addUser='.$accessKey);
echo 'https://nas.el-wa.org/smart?addUser='.$accessKey;
}
?>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,65 +1,65 @@
<?php
require_once("../helper.php");
if(!isset($_GET["TO"])){
$_GET["TO"] = 12;
}
$_GET["TO"] = intval($_GET["TO"]);
if(!isset($_GET["FROM"])){
$_GET["FROM"] = -24;
}
$_GET["FROM"] = intval($_GET["FROM"]);
$Query = "SELECT
UNIX_TIMESTAMP(CONCAT(date,' ',sunrise)) AS sunrise,
UNIX_TIMESTAMP(CONCAT(date,' ',sunset)) AS sunset
FROM solarLog.daylight
WHERE date BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"]-24)." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR)
ORDER BY date";
$linecolors["Solarleistung"] = "#FFFF00";
$linecolors["UG"] = "#FFaa00";
$linecolors["OG"] = "#FF4400";
$linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF";
$linecolors["Heizstab"] = "#FF0000";
$linecolors["Batterieladung"] = "#00aa00";
$linecolors["Einspeisung"] = "#b0b0b0";
$linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#2222FF";
if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $Query);
if (!$result) {
echo "Error:<br>" . mysqli_error($mysql) . "<br />";
}
//$obj[] = (object)[]; // Cast empty array to object
while ($row = $result->fetch_assoc()) {
$ii = 1;
$anno = (object)[];
if($row["sunrise"] < (time()+$_GET["FROM"]*60*60)){
$anno->xMin = (time()+$_GET["FROM"]*60*60)*1000;
}else{
$anno->xMin = $row["sunrise"]*1000;
}
if($row["sunset"] > (time()+$_GET["TO"]*60*60)){
$anno->xMax = round(time()+$_GET["TO"]*60*60)*1000;
}else{
$anno->xMax = $row["sunset"]*1000;
}
$anno->borderWidth = 0;
if($row["sunset"] > (time()+$_GET["FROM"]*60*60)){
$obj[] = clone $anno;
}
}
}
//header('Content-Type: application/json');
echo json_encode($obj);
//echo '{"labels":[1761322682000,1761322782000,1761322882000,1761322982000,1761323082000,1761323182000,1761323282000],"datasets":[{"stack": "Stack 0","cubicInterpolationMode":"monotone","fill":"origin","label":"Acquisitions by year","data":[10,20,50,20,10,5,70]},{"fill": "false","stack": "Stack 1","cubicInterpolationMode": "monotone","label": "Acquisitions by year","data": [10,20,50,20,10,5,70]}]}';
<?php
require_once("../helper.php");
if(!isset($_GET["TO"])){
$_GET["TO"] = 12;
}
$_GET["TO"] = intval($_GET["TO"]);
if(!isset($_GET["FROM"])){
$_GET["FROM"] = -24;
}
$_GET["FROM"] = intval($_GET["FROM"]);
$Query = "SELECT
UNIX_TIMESTAMP(CONCAT(date,' ',sunrise)) AS sunrise,
UNIX_TIMESTAMP(CONCAT(date,' ',sunset)) AS sunset
FROM solarLog.daylight
WHERE date BETWEEN DATE_ADD(NOW(),INTERVAL ".($_GET["FROM"]-24)." HOUR) and DATE_ADD(NOW(),INTERVAL ".$_GET["TO"]." HOUR)
ORDER BY date";
$linecolors["Solarleistung"] = "#FFFF00";
$linecolors["UG"] = "#FFaa00";
$linecolors["OG"] = "#FF4400";
$linecolors["Auto UG"] = "#00aaFF";
$linecolors["Auto OG"] = "#0044FF";
$linecolors["Heizstab"] = "#FF0000";
$linecolors["Batterieladung"] = "#00aa00";
$linecolors["Einspeisung"] = "#b0b0b0";
$linecolors["Ladestand"] = "#00aa00";
$linecolors["Vorhersage"] = "#2222FF";
if (checkLogin()) {
$mysql = new mysqli($mysql_server, $mysql_solarUser, $mysql_solarPass, $mysql_solarDB);
$result = mysqli_query($mysql, $Query);
if (!$result) {
echo "Error:<br>" . mysqli_error($mysql) . "<br />";
}
//$obj[] = (object)[]; // Cast empty array to object
while ($row = $result->fetch_assoc()) {
$ii = 1;
$anno = (object)[];
if($row["sunrise"] < (time()+$_GET["FROM"]*60*60)){
$anno->xMin = (time()+$_GET["FROM"]*60*60)*1000;
}else{
$anno->xMin = $row["sunrise"]*1000;
}
if($row["sunset"] > (time()+$_GET["TO"]*60*60)){
$anno->xMax = round(time()+$_GET["TO"]*60*60)*1000;
}else{
$anno->xMax = $row["sunset"]*1000;
}
$anno->borderWidth = 0;
if($row["sunset"] > (time()+$_GET["FROM"]*60*60)){
$obj[] = clone $anno;
}
}
}
//header('Content-Type: application/json');
echo json_encode($obj);
//echo '{"labels":[1761322682000,1761322782000,1761322882000,1761322982000,1761323082000,1761323182000,1761323282000],"datasets":[{"stack": "Stack 0","cubicInterpolationMode":"monotone","fill":"origin","label":"Acquisitions by year","data":[10,20,50,20,10,5,70]},{"fill": "false","stack": "Stack 1","cubicInterpolationMode": "monotone","label": "Acquisitions by year","data": [10,20,50,20,10,5,70]}]}';

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -1,144 +1,144 @@
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 200;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 200;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 200;
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;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 300;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 300;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 300;
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;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 400;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 400;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 400;
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;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 600;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 600;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 600;
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;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 700;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 700;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 700;
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;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 800;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 800;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 800;
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;
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 200;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 200;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 200;
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;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 300;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 300;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 300;
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;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 400;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 400;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 400;
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;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 600;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 600;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 600;
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;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 700;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 700;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 700;
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;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 800;
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;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 800;
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;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 800;
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;
}

View File

@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#fff"
class="bi bi-heart-arrow" viewBox="0 0 16 16">
<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" />
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#fff"
class="bi bi-heart-arrow" viewBox="0 0 16 16">
<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" />
</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%">
<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
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"
style="fill:#212529;fill-opacity:1;stroke-width:2;" />
<ellipse
ry="3"
rx="1"
cy="112"
cx="211"
id="path902" />
<ellipse
ry="5"
rx="3"
cy="163"
cx="211"
id="path904" />
<ellipse
ry="5"
rx="3"
cy="282"
cx="210"
id="path904-6" />
<ellipse
ry="5"
rx="3"
cy="345"
cx="213"
id="path904-2" />
<ellipse
ry="3"
rx="1"
cy="332"
cx="213"
id="path902-4" />
<ellipse
ry="3"
rx="1"
cy="121"
cx="100"
id="path902-0" />
<ellipse
ry="3"
rx="1"
cy="164"
cx="99" />
<ellipse
ry="3"
rx="1"
cy="175"
cx="99"
id="path902-8" />
<ellipse
ry="3"
rx="1"
cy="223"
cx="98"
id="path902-2" />
<ellipse
ry="3"
rx="1"
cy="257"
cx="98"
id="path902-07" />
<path
id="heatweRLtube1"
d="m 211,282 h 95 v -44"
style="fill:none;" />
<path
id="path976"
d="m 212,163 h 58"
style="fill:none;" />
<path
id="path978"
d="M 32,140 H 2 v 61 H 32 Z"
style="fill:none;stroke-width:1px;" />
<path
id="path980"
d="M 99,121 H 9 v 18"
style="fill:none;" />
<path
id="path982"
d="M 33,175 H 98"
style="fill:none;" />
<path
id="path984"
d="m 8,201 v 21 H 98"
style="fill:none;" />
<path
id="fbVLtube"
d="m 99,164 h 7 V 244 H 8 v 23"
style="fill:none;" />
<path
id="fbRLtube"
d="m 8,302 v 32 H 107 v -79 h -9"
style="fill:none;" />
<path
id="path990"
d="m 211,112 h 39 V 68"
style="fill:none;" />
<path
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"
style="fill:none;stroke-width:1px;" />
<path
id="path994"
d="M 28,167 H 5"
style="fill:none;stroke-width:1px;" />
<path
id="path996"
d="M 5,161 H 28"
style="fill:none;stroke-width:1px;" />
<path
id="path998"
d="M 27,156 H 7"
style="fill:none;stroke-width:1px;s" />
<path
id="path1000"
d="m 10,152 1,2 H 24 l 1,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1002"
d="m 24,167 v 5 h 4"
style="fill:none;stroke-width:1px;" />
<path
id="path1004"
d="M 47,268 H 1 v 34 H 47 v -34 z"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:none;stroke-width:1px;" />
<path
id="path1008"
d="M 294,238 Z"
style="fill:none;stroke-width:1px;" />
<path
id="heizerRLtube2"
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" />
<path
id="path1012"
d="M 270,163 Z"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:#212529;stroke-width:1px;" />
<path
id="path1020"
d="m 270,163 h 19 v 5"
style="fill:none;" />
<path
id="path1022"
d="m 282,247 c 0,0 -0,-2 2,-2"
style="fill:none;stroke-width:1px;" />
<path
id="path1024"
d="m 296,247 c 0,0 0,-2 -3,-3"
style="fill:none;stroke-width:1px;" />
<path
id="path976-2"
d="m 213,332 h 75"
style="fill:none;stroke-width:4;" />
<path
id="path1043"
d="m 240,338 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-9"
d="m 240,169 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-5"
d="m 65,228 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-3"
d="m 65,250 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-94"
d="m 253,288 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-94-5"
d="m 236,103 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-94-2"
d="m 65,342 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-94-6"
d="m 65,126 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-94-9"
d="m 65,180 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:none;stroke-width:1px;" />
<path
id="path1125"
d="m 266,68 -0,2"
style="fill:none;stroke-width:1px;" />
<path
id="path1127"
d="m 266,73 v 1"
style="fill:none;stroke-width:1px;" />
<path
id="path1129"
d="m 268,68 v 2"
style="fill:none;stroke-width:1px;" />
<path
id="path1131"
d="m 268,73 v 1"
style="fill:none;stroke-width:1px;" />
<path
id="path1133"
d="m 271,69 v 2"
style="fill:none;stroke-width:1px;" />
<path
id="path1135"
d="M 271,74 V 75"
style="fill:none;stroke-width:1px;" />
<path
id="path1137"
d="m 285,314 h -4 v 12 h 4"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:none;stroke-width:1px;" />
</g>
<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">
--.- °C
</text>
<text id="PufferMtxt" dy="400" dx="320">
--.- °C
</text>
<text id="PufferUtxt" dy="600" dx="320">
--.- °C
</text>
<text id="heaterRL" dy="505" dx="530" style="font-size: 22px;">
--.- °C
</text>
<text id="heaterVL" dy="260" dx="530" style="font-size: 22px;">
--.- °C
</text>
<text id="fbVL" dy="465" dx="70" style="font-size: 22px;">
--.- °C
</text>
<text id="fbRL" dy="605" dx="70" style="font-size: 22px;">
--.- °C
</text>
<text id="thermeRL" dy="385" dx="70" style="font-size: 22px;">
--.- °C
</text>
<text id="thermeVLfb" dy="290" dx="110" style="font-size: 22px;">
--.- °C
</text>
<text id="thermeVLww" dy="180" dx="70" style="font-size: 22px;">
--.- °C
</text>
<text id="triacLbl" dy="350" dx="515" style="font-size: 22px;">
Triac:
</text>
<text id="triac" dy="375" dx="515" style="font-size: 22px;">
--.- °C
</text>
</g>
<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)">
<path
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"
style="fill:#212529;fill-opacity:1;stroke-width:2;" />
<ellipse
ry="3"
rx="1"
cy="112"
cx="211"
id="path902" />
<ellipse
ry="5"
rx="3"
cy="163"
cx="211"
id="path904" />
<ellipse
ry="5"
rx="3"
cy="282"
cx="210"
id="path904-6" />
<ellipse
ry="5"
rx="3"
cy="345"
cx="213"
id="path904-2" />
<ellipse
ry="3"
rx="1"
cy="332"
cx="213"
id="path902-4" />
<ellipse
ry="3"
rx="1"
cy="121"
cx="100"
id="path902-0" />
<ellipse
ry="3"
rx="1"
cy="164"
cx="99" />
<ellipse
ry="3"
rx="1"
cy="175"
cx="99"
id="path902-8" />
<ellipse
ry="3"
rx="1"
cy="223"
cx="98"
id="path902-2" />
<ellipse
ry="3"
rx="1"
cy="257"
cx="98"
id="path902-07" />
<path
id="heatweRLtube1"
d="m 211,282 h 95 v -44"
style="fill:none;" />
<path
id="path976"
d="m 212,163 h 58"
style="fill:none;" />
<path
id="path978"
d="M 32,140 H 2 v 61 H 32 Z"
style="fill:none;stroke-width:1px;" />
<path
id="path980"
d="M 99,121 H 9 v 18"
style="fill:none;" />
<path
id="path982"
d="M 33,175 H 98"
style="fill:none;" />
<path
id="path984"
d="m 8,201 v 21 H 98"
style="fill:none;" />
<path
id="fbVLtube"
d="m 99,164 h 7 V 244 H 8 v 23"
style="fill:none;" />
<path
id="fbRLtube"
d="m 8,302 v 32 H 107 v -79 h -9"
style="fill:none;" />
<path
id="path990"
d="m 211,112 h 39 V 68"
style="fill:none;" />
<path
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"
style="fill:none;stroke-width:1px;" />
<path
id="path994"
d="M 28,167 H 5"
style="fill:none;stroke-width:1px;" />
<path
id="path996"
d="M 5,161 H 28"
style="fill:none;stroke-width:1px;" />
<path
id="path998"
d="M 27,156 H 7"
style="fill:none;stroke-width:1px;s" />
<path
id="path1000"
d="m 10,152 1,2 H 24 l 1,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1002"
d="m 24,167 v 5 h 4"
style="fill:none;stroke-width:1px;" />
<path
id="path1004"
d="M 47,268 H 1 v 34 H 47 v -34 z"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:none;stroke-width:1px;" />
<path
id="path1008"
d="M 294,238 Z"
style="fill:none;stroke-width:1px;" />
<path
id="heizerRLtube2"
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" />
<path
id="path1012"
d="M 270,163 Z"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:#212529;stroke-width:1px;" />
<path
id="path1020"
d="m 270,163 h 19 v 5"
style="fill:none;" />
<path
id="path1022"
d="m 282,247 c 0,0 -0,-2 2,-2"
style="fill:none;stroke-width:1px;" />
<path
id="path1024"
d="m 296,247 c 0,0 0,-2 -3,-3"
style="fill:none;stroke-width:1px;" />
<path
id="path976-2"
d="m 213,332 h 75"
style="fill:none;stroke-width:4;" />
<path
id="path1043"
d="m 240,338 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-9"
d="m 240,169 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-5"
d="m 65,228 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-3"
d="m 65,250 0,-2 -7,3 6,3 -0,-2 4,-0 -0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-94"
d="m 253,288 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-94-5"
d="m 236,103 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-94-2"
d="m 65,342 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-94-6"
d="m 65,126 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
id="path1043-94-9"
d="m 65,180 -0,-2 7,3 -6,3 0,-2 -4,-0 0,-2 z"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:none;stroke-width:1px;" />
<path
id="path1125"
d="m 266,68 -0,2"
style="fill:none;stroke-width:1px;" />
<path
id="path1127"
d="m 266,73 v 1"
style="fill:none;stroke-width:1px;" />
<path
id="path1129"
d="m 268,68 v 2"
style="fill:none;stroke-width:1px;" />
<path
id="path1131"
d="m 268,73 v 1"
style="fill:none;stroke-width:1px;" />
<path
id="path1133"
d="m 271,69 v 2"
style="fill:none;stroke-width:1px;" />
<path
id="path1135"
d="M 271,74 V 75"
style="fill:none;stroke-width:1px;" />
<path
id="path1137"
d="m 285,314 h -4 v 12 h 4"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:none;stroke-width:1px;" />
<path
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"
style="fill:none;stroke-width:1px;" />
</g>
<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">
--.- °C
</text>
<text id="PufferMtxt" dy="400" dx="320">
--.- °C
</text>
<text id="PufferUtxt" dy="600" dx="320">
--.- °C
</text>
<text id="heaterRL" dy="505" dx="530" style="font-size: 22px;">
--.- °C
</text>
<text id="heaterVL" dy="260" dx="530" style="font-size: 22px;">
--.- °C
</text>
<text id="fbVL" dy="465" dx="70" style="font-size: 22px;">
--.- °C
</text>
<text id="fbRL" dy="605" dx="70" style="font-size: 22px;">
--.- °C
</text>
<text id="thermeRL" dy="385" dx="70" style="font-size: 22px;">
--.- °C
</text>
<text id="thermeVLfb" dy="290" dx="110" style="font-size: 22px;">
--.- °C
</text>
<text id="thermeVLww" dy="180" dx="70" style="font-size: 22px;">
--.- °C
</text>
<text id="triacLbl" dy="350" dx="515" style="font-size: 22px;">
Triac:
</text>
<text id="triac" dy="375" dx="515" style="font-size: 22px;">
--.- °C
</text>
</g>
</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"
viewBox="-100 -100 1600 950" width="100%" height="100%" id="realtimeSvgAni">
<defs>
<filter id="shadow" x="-0.5" y="-0.5" width="200%" height="200%">
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
<feMorphology in="offOut" result="offOut" operator="dilate" radius="0.7" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="0.5" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
<filter id="shadowMiddle" x="-1.0" y="-1.0" width="300%" height="300%">
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
<feMorphology in="offOut" result="offOut" operator="dilate" radius="3" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="1" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
<filter id="shadowBig" x="-1" y="-1" width="300%" height="300%">
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
<feMorphology in="offOut" result="offOut" operator="dilate" radius="3" />
<feGaussianBlur result="offOut" in="offOut" stdDeviation="2" />
<feBlend in="SourceGraphic" in2="offOut" mode="normal" />
</filter>
<g id="circGrid">
<line x2='27.7' y2='76.5' x1='-18.9' y1='61.4' style='stroke-width:4px' />
<line x2='16.5' y2='115.9' x1='-8.1' y1='120.6' style='stroke:#222;stroke-width:2;' />
<line x2='34.5' y2='154.2' x1='15.2' y1='170.1' style='stroke:#222;stroke-width:2;' />
<line x2='68.7' y2='179' x1='59.5' y1='202.3' style='stroke:#222;stroke-width:2;' />
<line x2='110.7' y2='184.3' x1='113.8' y1='209.1' style='stroke:#222;stroke-width:2;' />
<line x2='150' y2='168.8' x1='164.7' y1='189' style='stroke:#222;stroke-width:2;' />
<line x2='176.9' y2='136.2' x1='199.5' y1='146.8' style='stroke:#222;stroke-width:2;' />
<line x2='184.8' y2='94.7' x1='209.8' y1='93.1' style='stroke:#222;stroke-width:2;' />
<line x2='171.8' y2='54.5' x1='192.9' y1='41.1' style='stroke:#222;stroke-width:2;' />
<line x2='140.9' y2='25.5' x1='153' y1='3.6' style='stroke:#222;stroke-width:2;' />
<line x2='100' y2='24' x1='100' y1='-24' style='stroke-width:4px' />
</g>
<g id="circGrid6kW">
<line x2='27.7' y2='76.5' x1='-18.9' y1='61.4' style='stroke-width:4px' />
<line x2='26.4' y2='142.5' x1='4.7' y1='155' style='stroke:#222;stroke-width:2;' />
<line x2='82.3' y2='183.1' x1='77.1' y1='207.6' style='stroke:#555;stroke-width:4px;' />
<line x2='149.9' y2='168.8' x1='164.6' y1='189.0' style='stroke:#222;stroke-width:2;' />
<line x2='184.5' y2='108.9' x1='209.4' y1='111.5' style='stroke:#555;stroke-width:4px;' />
<line x2='163.2' y2='43.1' x1='181.7' y1='26.4' style='stroke:#222;stroke-width:2;' />
<line x2='100' y2='24' x1='100' y1='-24' style='stroke-width:4px' />
</g>
<linearGradient id="gradient1" x1="0" x2="0" y1="0" y2="1">
<stop id="tmpH" offset="0%" stop-color="#2389BA" stop-opacity="0.7" />
<stop id="tmpM" offset="50%" stop-color="#2389BA" stop-opacity="0.7" />
<stop id="tmpL" offset="100%" stop-color="#2389BA" stop-opacity="0.7" />
</linearGradient>
<filter id="fillpartialEV" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%">
<feFlood flood-color="#1f5a66" />
<feComposite id="evChargeState" y="100%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" />
</filter>
<filter id="fillpartialHeat" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%">
<feFlood flood-color="#5E2B21" />
<feComposite id="heatChargeState" y="100%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" />
</filter>
<filter id="fillpartialBat" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%">
<feFlood flood-color="#25481C" />
<feComposite id="batChargeState" y="100%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" />
</filter>
<filter id="fillpartialWater" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%">
<feFlood flood-color="#182C43" />
<feComposite id="waterState" y="50%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" />
</filter>
<g id="heater" transform="rotate(-90),scale(0.07,0.07)">
<path
d="M485.924,134.508c14.381,0,26.076-11.669,26.076-26.017v-17.39c0-14.348-11.695-26.017-26.076-26.017H468.61v-8.737
c0-23.89-19.466-43.331-43.39-43.331s-43.39,19.441-43.39,43.331v8.737h-26.034v-8.737c0-23.89-19.466-43.331-43.39-43.331
c-23.924,0-43.39,19.441-43.39,43.331v8.737h-26.034v-8.737c0-23.89-19.466-43.331-43.39-43.331
c-23.924,0-43.39,19.441-43.39,43.331v8.737h-26.034v-8.737c0-23.89-19.466-43.331-43.39-43.331S43.39,32.458,43.39,56.348v8.737
H17.356V39.051H0v34.712v52.068v34.712h17.356v-26.034H43.39v269.017H8.678c-4.797,0-8.678,3.881-8.678,8.678v34.712
c0,4.797,3.881,8.678,8.678,8.678c4.797,0,8.678-3.881,8.678-8.678v-26.034H43.39v34.78c0,23.89,19.466,43.322,43.39,43.322
s43.39-19.432,43.39-43.322v-0.068h26.034v0.068c0,23.89,19.466,43.322,43.39,43.322c23.924,0,43.39-19.432,43.39-43.322v-0.068
h26.034v0.068c0,23.89,19.466,43.322,43.39,43.322c23.924,0,43.39-19.432,43.39-43.322v-0.068h26.034v0.068
c0,23.89,19.466,43.322,43.39,43.322s43.39-19.432,43.39-43.322v-0.068h17.314c14.381,0,26.076-11.669,26.076-26.017v-17.39
c0-14.347-11.695-26.017-26.076-26.017H468.61V134.508H485.924z M468.61,82.441h17.314c4.805,0,8.72,3.881,8.72,8.661v17.39
c0,4.78-3.915,8.661-8.72,8.661H468.61V82.441z M43.39,117.153H17.356V82.441H43.39V117.153z M112.814,73.763v52.068v269.017
v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966V125.831V73.763V56.348
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M156.203,438.237h-26.034v-34.712h26.034V438.237z
M156.203,386.169h-26.034V134.508h26.034V386.169z M156.203,117.153h-26.034V82.441h26.034V117.153z M225.627,73.763v52.068
v269.017v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966v-8.746v-52.068V125.831V73.763V56.348
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M269.017,438.237h-26.034v-34.712h26.034V438.237z
M269.017,386.169h-26.034V134.508h26.034V386.169z M269.017,117.153h-26.034V82.441h26.034V117.153z M338.441,73.763v52.068
v269.017v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966v-8.746v-52.068V125.831V73.763V56.348
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M381.831,438.237h-26.034v-34.712h26.034V438.237z
M381.831,386.169h-26.034V134.508h26.034V386.169z M381.831,117.153h-26.034V82.441h26.034V117.153z M451.254,73.763v52.068
v269.017v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966v-8.746v-52.068V125.831V73.763V56.348
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M485.924,403.525c4.805,0,8.72,3.881,8.72,8.661
v17.39c0,4.78-3.915,8.661-8.72,8.661H468.61v-34.712H485.924z" />
</g>
<g id="gas">
<path fill-opacity="1" stroke-width="0.2" stroke-linejoin="round"
d="M 42.75,19L 42.75,31.4977C 44.5834,31.378 48.9184,32.7881 48.2917,49.0833C 49.0833,53.8333 54.625,53.8333 55.8125,47.5C 57,42.75 53.8333,42.75 52.25,28.5C 52.25,26.9167 52.25,22.1667 45.9167,19L 45.9167,17.4167C 52.25,17.4167 57,25.3333 57,26.9167C 57,28.5 55.4167,28.5 55.4167,28.5C 55.4167,28.5 55.8125,38 57.3958,39.5833C 58.9792,41.1667 58.5833,45.9167 58.5833,49.0833C 58.5833,52.25 53.8333,55.4167 52.25,55.4167C 50.6667,55.4167 45.9167,55.4167 45.9167,50.6667C 45.9167,46.3403 45.2599,36.7598 42.75,35.0854L 42.75,55.4167C 43.6244,55.4167 44.3333,56.1255 44.3333,57L 44.3333,60.1667L 19,60.1667L 19,57C 19,56.1255 19.7089,55.4167 20.5833,55.4167L 20.5833,19C 20.5833,17.2511 22.0011,15.8333 23.75,15.8333L 39.5833,15.8333C 41.3322,15.8333 42.75,17.2511 42.75,19 Z M 25.7291,33.2501L 37.6041,33.25C 38.4786,33.25 39.5833,32.1453 39.5833,31.2709L 39.5833,20.9792C 39.5833,20.1048 38.4786,19 37.6041,19L 25.7292,19C 24.8547,19 23.75,20.1048 23.75,20.9792L 23.75,31.2709C 23.75,32.1453 24.8547,33.2501 25.7291,33.2501 Z " />
</g>
<g id="water">
<path
d="M283.897,92.846c-36.582-49.345-73.688-89.267-74.061-89.664C207.944,1.153,205.296,0,202.523,0
c-2.774,0-5.423,1.152-7.314,3.182c-0.371,0.397-37.478,40.319-74.06,89.664c-49.971,67.403-75.308,119.726-75.308,155.513
c0,86.396,70.287,156.688,156.682,156.688c86.396,0,156.683-70.29,156.683-156.688C359.206,212.572,333.868,160.25,283.897,92.846z
M218.171,354.342c-8.213,1.941-16.68,2.926-25.162,2.926c-60.294,0-109.347-49.055-109.347-109.35
c0-8.312,2.559-23.373,14.75-47.914c1.225-2.467,4.046-3.691,6.687-2.908c2.639,0.785,4.33,3.357,4.007,6.091
c-0.28,2.361-0.421,4.584-0.421,6.607c0,64.629,45.966,120.77,109.298,133.484c2.607,0.525,4.5,2.795,4.545,5.455
C222.575,351.396,220.761,353.729,218.171,354.342z" />
</g>
<g id="voltage">
<path stroke="#212529" stroke-width="0.2px" d="M11.46,18V13.58H9.86L12.54,8v3.89h1.6Z" />
</g>
<path id="powerTextPath" d="M 100, 100 m -87, 0 a 87,87 0 1,1 174,0 a 87,87 0 1,1 -174,0"></path>
<path id="infoTextPath" d="M 100, 100 m -105, 0 a 105,105 0 1,0 210,0 a 105,105 0 1,0 -210,0"></path>
<g id="pvPlate" fill="none" stroke-width="4" stroke="#f7c000">
<rect width="70" height="40" x="0" y="0" rx="5" ry="5" />
</g>
<g id="ElementBG">
<path fill="#212529" stroke-width="1.5"
d="M 99.80277789465349 -12.999827891201505 A 113 113 0 1 0 100 -13" />
<path fill="none" stroke-width="4"
d="M 99.86386438745993 22.00011880076356 A 78 78 0 1 0 100 22" />
</g>
<g id="plugIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)" fill="#71afcd">
<path d="M15.21,6.73V2.63A.72.72,0,0,0,14.4,2h0a.71.71,0,0,0-.75.66V6.73Z" />
<path d="M10.39,6.73V2.62A.7.7,0,0,0,9.6,2h0a.73.73,0,0,0-.78.66V6.73Z" />
<path
d="M6.71,7.23C6.37,7.22,6,8,6,8.8V10c0,2.48.57,4.62,1.63,5.28S9,16,10.35,16.77V22h3.3V16.77c1.38-.8,1.66-.85,2.72-1.51S18,12.46,18,10V8.8c0-.78-.37-1.58-.71-1.57Z" />
</g>
<g id="ogIcon" filter="url(#shadow)" transform="translate(52,45),scale(4,4)">
<polygon fill="#70CCBB"
points="12.01 1.5 2 10.32 3.11 10.32 3.11 21.5 5.12 21.5 5.12 10.32 12 4.13 18.89 10.32 18.89 21.5 20.89 21.5 20.89 10.32 22 10.32 12.01 1.5" />
<path fill="#70CCBB"
d="M8.55,12.65v3.49a2.12,2.12,0,0,0,2.13,2.09h.67s0,3.23,0,3.27h1.49s0-3.24,0-3.28h.77a1.82,1.82,0,0,0,1.8-1.85l0-3.73" />
<path fill="#70CCBB" d="M10.76,11.41v-1.3c0-.45-.17-.67-.52-.68s-.54.22-.54.69v1.67h1.06Z" />
<path fill="#70CCBB"
d="M14.3,11.41c0-.44,0-.88,0-1.3s-.17-.67-.51-.68-.55.22-.55.69v1.67H14.3Z" />
<path fill="#212529"
d="M9.86,13.86h4.28a0,0,0,0,1,0,0v2a1,1,0,0,1-1,1H10.86a1,1,0,0,1-1-1v-2A0,0,0,0,1,9.86,13.86Z" />
</g>
<g id="heatIcon" filter="url(#shadow)" transform="translate(52,70),scale(4,4)" fill="#C2614E">
<path clip-path="M-22 2.24h42V22h-42z"
d="M16.543 8.028c-.023 1.503-.523 3.538-2.867 4.327.734-1.746.846-3.417.326-4.979-.695-2.097-3.014-3.735-4.557-4.627-.527-.306-1.203.074-1.193.683.02 1.112-.318 2.737-1.959 4.378C4.107 9.994 3 12.251 3 14.517 3 17.362 5 21 9 21c-4.041-4.041-1-7.483-1-7.483C8.846 19.431 12.988 21 15 21c1.711 0 5-1.25 5-6.448 0-3.133-1.332-5.511-2.385-6.899-.347-.458-1.064-.198-1.072.375" />
</g>
<g id="ugIcon" filter="url(#shadow)" transform="translate(52,50),scale(4,4)">
<rect stroke="#70CC9C" stroke-width="2" fill="none" x="3" y="3" width="18" height="18" rx="2" />
<path fill="#70CC9C"
d="M8.55,9.2v3.47a2.11,2.11,0,0,0,2.13,2.08h.67s0,3.22,0,3.26h1.49s0-3.22,0-3.26h.77a1.81,1.81,0,0,0,1.8-1.84l0-3.71" />
<path fill="#70CC9C" d="M10.76,8V6.67c0-.45-.17-.66-.52-.67s-.54.22-.54.68V8.34h1.06Z" />
<path fill="#70CC9C" d="M14.3,8c0-.44,0-.87,0-1.3S14.12,6,13.78,6s-.55.22-.55.68V8.34H14.3Z" />
<path fill="#212529"
d="M9.86,10.41h4.28a0,0,0,0,1,0,0v2a1,1,0,0,1-1,1H10.86a1,1,0,0,1-1-1v-2A0,0,0,0,1,9.86,10.41Z" />
</g>
<g id="carIcon" filter="url(#shadow)" transform="translate(45,45),scale(4.8,4.8)"
fill="#212529" stroke-linecap="round">
<path d="M16.22,15.37l-9.3-.16L3,15,.88,14.47.75,10.39A2.78,2.78,0,0,1,1.31,9.2L2.55,7.63" />
<path
d="M.78,7.46,7,7l.87,0L11.37,7a5.57,5.57,0,0,1,1.06.23,9.43,9.43,0,0,1,2.16,1L17.23,9.9l4.22.7a1.73,1.73,0,0,1,1.21.93l.26.49a2.84,2.84,0,0,1,.32,1.6l0,.23A1.52,1.52,0,0,1,22.53,15h0a1.53,1.53,0,0,1-.56.21l-.89.15H15.59" />
<path fill="#888888" stroke="none"
d="M16.06,11c-1.85.11-3.7.14-5.55.16a13.36,13.36,0,0,1-2.82,0,2.62,2.62,0,0,1-.87-.4,1.28,1.28,0,0,1-.53-1.05,1.4,1.4,0,0,1,.09-.51,2.67,2.67,0,0,1,.22-.35,2.79,2.79,0,0,1,.5-.58s.09,0,.11,0a.06.06,0,0,1,0,.05h0c0,.25,0,.49,0,.71s0,.23,0,.31a.75.75,0,0,0,.08.18c.07.09.17.14.17.08a1.81,1.81,0,0,0,.43.05,14.41,14.41,0,0,1,2.68.33c1.82.26,3.64.53,5.46.88a.08.08,0,0,1,.06.09A.07.07,0,0,1,16.06,11Z" />
<circle cx="4.94" cy="15.08" r="1.98" />
<circle cx="19.19" cy="15.08" r="1.98" />
</g>
<g id="plugCordIcon" transform="scale(0.08,0.08),rotate(340),translate(-350,1200)">
<path
d="M489.8,280.92c0-13.9-11.3-25.2-25.2-25.2h-74.1c-62.1,0-112.4,50.2-112.7,112.2c-0.1,32.3-23,61-55,65
c-38.4,4.8-71.2-25.2-71.2-62.6v-56.4c57.6-11.7,101-62.6,101-123.7v-64c0-9.1-7.3-16.4-16.4-16.4h-31.3v-79.1
c0-12.4-9-23.4-21.3-24.6c-14.1-1.4-26,9.7-26,23.6v80.1H95.2v-79.1c0-12.4-9-23.4-21.4-24.6c-14.1-1.3-26,9.7-26,23.6v80.1H16.4
c-9.1,0-16.4,7.3-16.4,16.4v64c0,61.1,43.4,112,101,123.7v53.5c0,61.5,47.7,114,109.2,116.3c64.6,2.4,118-49.4,118-113.5v-0.9
c0-34.9,28.3-63.1,63.1-63.1h73.2C478.5,306.12,489.8,294.82,489.8,280.92L489.8,280.92z" />
</g>
<g id="lockIcon" transform="translate(80,130),scale(0.11,0.11)" style="">
<path
d="M65,330h200c8.284,0,15-6.716,15-15V145c0-8.284-6.716-15-15-15h-15V85c0-46.869-38.131-85-85-85
S80,38.131,80,85v45H65c-8.284,0-15,6.716-15,15v170C50,323.284,56.716,330,65,330z M207.481,219.356l-42.5,42.5
c-2.929,2.929-6.768,4.394-10.606,4.394s-7.678-1.465-10.606-4.394l-21.25-21.25c-5.858-5.858-5.858-15.354,0-21.213
c5.857-5.858,15.355-5.858,21.213,0l10.644,10.643l31.894-31.893c5.857-5.858,15.355-5.858,21.213,0
C213.34,204.002,213.34,213.498,207.481,219.356z M110,85c0-30.327,24.673-55,55-55s55,24.673,55,55v45H110V85z"
style="stroke-width:15px;stroke:rgb(30,30,40);fill:#778;" />
</g>
<g filter="url(#shadow)" id="clock" style="fill:#cc0;"
transform="translate(80,32),scale(0.07,0.07)">
<path
d="m256,51.8c-112.6,0-204.2,91.6-204.2,204.2s91.6,204.2 204.2,204.2 204.2-91.6 204.2-204.2-91.6-204.2-204.2-204.2v-1.42109e-14zm0,449.2c-135.1,0-245-109.9-245-245s109.9-245 245-245 245,109.9 245,245-109.9,245-245,245z" />
<path
d="m327.9,276.4h-71.9c-11.3,0-20.4-9.1-20.4-20.4v-132.2c0-11.3 9.1-20.4 20.4-20.4 11.3,0 20.4,9.1 20.4,20.4v111.8h51.5c11.3,0 20.4,9.1 20.4,20.4s-9.1,20.4-20.4,20.4z" />
</g>
<g id="sunIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)"
style="stroke:#f7c000;stroke-width:2;stroke-linecap:round;">
<path id="Pfad_7565" data-name="Pfad 7565" fill="#f7c002" stroke-width="0"
d="M12,8a4,4,0,1,0,4,4A4,4,0,0,0,12,8Z" />
<line x1="12" y1="3" x2="12" y2="5" />
<line x1="12" y1="19" x2="12" y2="21" />
<line x1="19" y1="12" x2="21" y2="12" />
<line x1="3" y1="12" x2="5" y2="12" />
<line x1="5.7" y1="18.5" x2="7" y2="17" />
<line x1="5.7" y1="5.7" x2="7" y2="7" />
<line x1="18.5" y1="18.5" x2="16.7" y2="17" />
<line x1="18.5" y1="5.7" x2="16.7" y2="7" />
</g>
<g id="battIcon" filter="url(#shadow)" transform="translate(30,25),scale(6,6)">
<g>
<rect fill="#6cbe58" x="9.25" y="3" width="5.5" height="4" rx="1" ry="1" />
<path fill="#6cbe58"
d="M16.28,5H7.72A1.21,1.21,0,0,0,6.5,6.2V19.73A1.28,1.28,0,0,0,7.72,21h8.56a1.28,1.28,0,0,0,1.22-1.27V6.2A1.21,1.21,0,0,0,16.28,5Z" />
<rect id="discharged" fill="#212529" rx="1" ry="1" x="8" y="6.5" width="8"
height="13" />
<use id="charge" fill="#cccc00" href="#voltage" />
</g>
</g>
<g id="gridIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)">
<path fill="#808090"
d="M13.38,8.54V6.63H18.3V8.06h.95V5.7l-6.35-1L12,2l-1,2.8-6.25.9V8.07H5.6V6.63h4.84V8.54l-7.59,1.9v2.84H3.8V11.76H9.87L6.93,22H9.11l.57-2.46h4.59L14.8,22h2.27L14.13,11.76H20.2v1.52h.95V10.44Zm-3.32,8.81L12,11.11l1.91,6.24Z" />
</g>
<g id="inverterIcon" filter="url(#shadowBig)" fill="#b2b2b2" stroke-width="2px" stroke="#666"
transform="translate(43,43),scale(1.6,1.6)">
<rect stroke-width="2px" x="5.65" y="3" width="58.7" height="64" rx="6.8" />
<circle cx="35.03" cy="29.61" r="11" />
<circle cx="15" cy="40" r="4" />
<path
d="M40.19,52H36.73a2,2,0,0,0-3.46,0H29.81a1.08,1.08,0,1,0,0,2.15h3.46a2,2,0,0,0,3.46,0h3.46a1.08,1.08,0,1,0,0-2.15Z" />
<path fill="#e2001a"
d="M34.89,61.87c-3.24,0-5.87-.73-5.87-1.62s2.63-1.64,5.87-1.64,5.87.74,5.87,1.64S38.13,61.87,34.89,61.87Z" />
<line x1="5.07" y1="53.08" x2="28.73" y2="53.08" />
<line x1="41.27" y1="53.08" x2="64.93" y2="53.08" />
</g>
<g id="northIcon" fill="#808090">
<path
d="M42.066 0v20h3.752V6.957L53.881 20h4.053V0h-3.752v13.355L45.996 0zm5.57 26.688l-25.77 69.949c-.823 2.238 1.658 4.248 3.677 2.978L50 84.195l24.455 15.42c2.02 1.273 4.504-.738 3.68-2.978l-25.79-70c-.472-1.096-1.283-1.632-2.384-1.635c-1.1-.003-2.017.856-2.324 1.686zm-.136 14.83V79.86L29.1 91.463z"></path>
</g>
<g filter="url(#shadow)" id="ecoIcon" transform="translate(60,12)">
<path style="stroke:#6cbe58;fill:rgb(30,30,40);" stroke-width="3" stroke-linejoin="round"
d="M 57,22.1667C 49.0833,28.5 52.25,31.6667 50.6667,36.4167C 49.0833,41.1667 50.6667,42.75 44.3333,47.5C 36.2227,53.583 29.2917,49.875 29.2917,49.875C 27.7083,51.4583 21.7708,54.2292 21.7708,54.2292L 20.0143,50.7285C 26.3476,49.1452 27.7083,47.1042 27.7083,47.1042C 26.125,43.9375 23.75,38 28.5,30.0833C 33.25,22.1667 57,22.1667 57,22.1667 Z M 30.0833,44.3333L 31.6667,45.9167C 31.6667,45.9167 34.8333,44.3333 36.4167,39.5833C 38,34.8333 45.9167,26.9167 45.9167,26.9167C 42.75,28.5 36.4167,34.8333 34.8333,39.5833C 33.25,44.3333 30.0833,44.3333 30.0833,44.3333 Z " />
</g>
<g filter="url(#shadow)" id="alertIcon" fill="#aa0" transform="translate(34,28),scale(2.2,2.2)">
<path
d="M214.413,746a4.455,4.455,0,0,1-3.84-2.166,4.249,4.249,0,0,1,0-4.334l25.572-43.331a4.483,4.483,0,0,1,7.679,0L269.4,739.5a4.249,4.249,0,0,1,0,4.334,4.452,4.452,0,0,1-3.84,2.166H214.413ZM240,706a4,4,0,0,0-4,4v16a4,4,0,0,0,8,0V710A4,4,0,0,0,240,706Zm0,36a4,4,0,1,0-4-4A4,4,0,0,0,240,742Z"
id="attention" transform="translate(-209.969 -694)" />
</g>
</defs>
<g id="pvDetail" opacity="1" transform="scale(1,1)">
<g id="pvInfo" transform="translate(80,30)" class="clickable" onclick="displayOverlay('realtime')">
<!--<g
filter="url(#glow)">-->
<use href="#ElementBG" stroke="#574400" />
<use href="#sunIcon" />
<path id="pvArc" fill="none" stroke="#f7c000" stroke-width="30" />
<path id="pv2Arc" fill="none" stroke="#f78d00" stroke-width="30" />
<path id="pv3Arc" fill="none" stroke="#f72300" stroke-width="30" />
<use href="#circGrid" style="stroke:#574400;" />
<!--</g>-->
<text filter="url(#shadowMiddle)" class="powerTextClass">
<textPath id="pvText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
<textPath id="pv3txt" href="#infoTextPath" startOffset="12%">--.-- kW</textPath>
<textPath id="pv2txt" href="#infoTextPath" startOffset="35%">--.-- kW</textPath>
<textPath id="pv1txt" href="#infoTextPath" startOffset="55%">--W</textPath>
</text>
</g>
<animate begin="openDetails.begin" attributetype="CSS" attributeName="opacity" from="0"
to="1.0"
dur="0.7s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze" />
<animateTransform attributeName="transform"
type="scale"
from="0.1,0.1"
to="1,1"
begin="openDetails.begin"
dur="0.3s" repeatCount="1" fill="freeze" />
<animate begin="closeDetails.click" attributetype="CSS" attributeName="opacity" from="1.0"
to="0"
dur="0.4s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze" />
<animateTransform attributeName="transform"
type="scale"
from="1,1"
to="0.1,0.1"
begin="closeDetails.click"
dur="0.7s" repeatCount="1" fill="freeze" />
<use href="#northIcon" transform="translate(1200,10),rotate(10)" />
<polygon points="370 0, 1300 0, 1300 700, 0 700, 0 250, 370 250" fill="rgb(24, 27, 31)" />
<polygon points="560,80 720,80 720,300 1160,300 1160,370 560,370" stroke-linejoin="round"
fill="#f7c002" stroke-width="30" stroke="#f7c002" opacity="0.1" />
<use href="#pvPlate" transform="translate(600,80), rotate(90)" />
<use href="#pvPlate" transform="translate(600,150), rotate(90)" />
<use href="#pvPlate" transform="translate(600,220), rotate(90)" />
<use href="#pvPlate" transform="translate(600,290), rotate(90)" />
<use href="#pvPlate" transform="translate(640,80), rotate(90)" />
<use href="#pvPlate" transform="translate(640,150), rotate(90)" />
<use href="#pvPlate" transform="translate(640,220), rotate(90)" />
<use href="#pvPlate" transform="translate(640,290), rotate(90)" />
<use href="#pvPlate" transform="translate(680,80), rotate(90)" />
<use href="#pvPlate" transform="translate(680,150), rotate(90)" />
<use href="#pvPlate" transform="translate(680,220), rotate(90)" />
<use href="#pvPlate" transform="translate(680,290), rotate(90)" />
<use href="#pvPlate" transform="translate(720,80), rotate(90)" />
<use href="#pvPlate" transform="translate(720,150), rotate(90)" />
<use href="#pvPlate" transform="translate(720,220), rotate(90)" />
<use href="#pvPlate" transform="translate(790,290)" />
<use href="#pvPlate" transform="translate(720,330)" />
<use href="#pvPlate" transform="translate(790,330)" />
<use href="#pvPlate" transform="translate(870,290)" />
<use href="#pvPlate" transform="translate(870,330)" />
<use href="#pvPlate" transform="translate(940,330)" />
<use href="#pvPlate" transform="translate(1160,300), rotate(90)" />
<use href="#pvPlate" transform="translate(1120,300), rotate(90)" />
<use href="#pvPlate" transform="translate(1080,300), rotate(90)" />
<text id="det_pv0P" filter="url(#shadowBig)" class="infoTextClass" dx="55" dy="30"
transform="translate(560, 150), scale(1.5,1.5)">-.-- kW</text>
<polygon points="980,60 1160,60 1160,265 980,265" stroke-linejoin="round" fill="#F76D00"
stroke-width="30" stroke="#F76D00" opacity="0.1" />
<use href="#pvPlate" transform="translate(1160,200), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1115,200), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1070,200), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1160,130), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1115,130), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1070,130), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1025,130), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1160,60), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1115,60), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1070,60), rotate(90), scale(1,1.125)" />
<text id="det_pv1P" filter="url(#shadowBig)" class="infoTextClass" dx="55" dy="30"
transform="translate(990, 140), scale(1.5,1.5)">-.-- kW</text>
<use href="#pvPlate" x="200" y="680" />
<text id="det_pv33P" filter="url(#shadowMiddle)" class="infoTextClass" x="200" y="680"
dx="36"
dy="26">#19</text>
<use href="#pvPlate" x="380" y="550" />
<text id="det_pv32P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="550"
dx="36"
dy="26">#19</text>
<use href="#pvPlate" x="380" y="590" />
<text id="det_pv31P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="590"
dx="36"
dy="26">#18</text>
<use href="#pvPlate" x="380" y="630" />
<text id="det_pv30P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="630"
dx="36"
dy="26">#17</text>
<use href="#pvPlate" x="310" y="510" />
<text id="det_pv29P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="510"
dx="36"
dy="26">#16</text>
<use href="#pvPlate" x="310" y="550" />
<text id="det_pv28P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="550"
dx="36"
dy="26">#15</text>
<use href="#pvPlate" x="310" y="590" />
<text id="det_pv27P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="590"
dx="36"
dy="26">#14</text>
<use href="#pvPlate" x="310" y="630" />
<text id="det_pv26P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="630"
dx="36"
dy="26">#13</text>
<use href="#pvPlate" x="240" y="510" />
<text id="det_pv25P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="510"
dx="36"
dy="26">#12</text>
<use href="#pvPlate" x="240" y="550" />
<text id="det_pv24P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="550"
dx="36"
dy="26">#11</text>
<use href="#pvPlate" x="240" y="590" />
<text id="det_pv23P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="590"
dx="36"
dy="26">#10</text>
<use href="#pvPlate" x="240" y="630" />
<text id="det_pv22P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="630"
dx="36"
dy="26">#9</text>
<use href="#pvPlate" x="170" y="510" />
<text id="det_pv21P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="510"
dx="36"
dy="26">#8</text>
<use href="#pvPlate" x="170" y="550" />
<text id="det_pv20P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="550"
dx="36"
dy="26">#7</text>
<use href="#pvPlate" x="170" y="590" />
<text id="det_pv19P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="590"
dx="36"
dy="26">#6</text>
<use href="#pvPlate" x="170" y="630" />
<text id="det_pv18P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="630"
dx="36"
dy="26">#5</text>
<use href="#pvPlate" x="100" y="510" />
<text id="det_pv14P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="510"
dx="36"
dy="26">#1</text>
<use href="#pvPlate" x="100" y="550" />
<text id="det_pv15P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="550"
dx="36"
dy="26">#2</text>
<use href="#pvPlate" x="100" y="590" />
<text id="det_pv16P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="590"
dx="36"
dy="26">#3</text>
<use href="#pvPlate" x="100" y="630" />
<text id="det_pv17P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="630"
dx="36"
dy="26">#4</text>
<use href="#pvPlate" transform="translate(600,500)" />
<text id="det_pv13P" filter="url(#shadowMiddle)" class="infoTextClass" x="600" y="500"
dx="36"
dy="26">- W</text>
<use href="#pvPlate" transform="translate(500,500)" />
<text id="det_pv12P" filter="url(#shadowMiddle)" class="infoTextClass" x="500" y="500"
dx="36"
dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,120), rotate(-90)" />
<text id="det_pv5P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,120), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,190), rotate(-90)" />
<text id="det_pv4P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,190), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,270), rotate(-90)" />
<text id="det_pv9P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,270), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,340), rotate(-90)" />
<text id="det_pv8P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,340), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,420), rotate(-90)" />
<text id="det_pv11P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,420), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,490), rotate(-90)" />
<text id="det_pv10P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,490), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,120), rotate(-90)" />
<text id="det_pv7P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,120), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,190), rotate(-90)" />
<text id="det_pv6P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,190), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,270), rotate(-90)" />
<text id="det_pv3P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,270), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,340), rotate(-90)" />
<text id="det_pv2P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,340), rotate(-90)" dx="36" dy="26">- W</text>
<text id="invList" filter="url(#shadowMiddle)" class="tooltipTextClass"
transform="translate(80,255)"></text>
<rect width="305" height="210" x="70" y="250" rx="5" ry="5" fill="none" stroke-width="4px"
stroke="#f7c000" />
</g>
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="-100 -100 1600 950" width="100%" height="100%" id="realtimeSvgAni">
<defs>
<filter id="shadow" x="-0.5" y="-0.5" width="200%" height="200%">
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
<feMorphology in="offOut" result="offOut" operator="dilate" radius="0.7" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="0.5" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
<filter id="shadowMiddle" x="-1.0" y="-1.0" width="300%" height="300%">
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
<feMorphology in="offOut" result="offOut" operator="dilate" radius="3" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="1" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
<filter id="shadowBig" x="-1" y="-1" width="300%" height="300%">
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
<feMorphology in="offOut" result="offOut" operator="dilate" radius="3" />
<feGaussianBlur result="offOut" in="offOut" stdDeviation="2" />
<feBlend in="SourceGraphic" in2="offOut" mode="normal" />
</filter>
<g id="circGrid">
<line x2='27.7' y2='76.5' x1='-18.9' y1='61.4' style='stroke-width:4px' />
<line x2='16.5' y2='115.9' x1='-8.1' y1='120.6' style='stroke:#222;stroke-width:2;' />
<line x2='34.5' y2='154.2' x1='15.2' y1='170.1' style='stroke:#222;stroke-width:2;' />
<line x2='68.7' y2='179' x1='59.5' y1='202.3' style='stroke:#222;stroke-width:2;' />
<line x2='110.7' y2='184.3' x1='113.8' y1='209.1' style='stroke:#222;stroke-width:2;' />
<line x2='150' y2='168.8' x1='164.7' y1='189' style='stroke:#222;stroke-width:2;' />
<line x2='176.9' y2='136.2' x1='199.5' y1='146.8' style='stroke:#222;stroke-width:2;' />
<line x2='184.8' y2='94.7' x1='209.8' y1='93.1' style='stroke:#222;stroke-width:2;' />
<line x2='171.8' y2='54.5' x1='192.9' y1='41.1' style='stroke:#222;stroke-width:2;' />
<line x2='140.9' y2='25.5' x1='153' y1='3.6' style='stroke:#222;stroke-width:2;' />
<line x2='100' y2='24' x1='100' y1='-24' style='stroke-width:4px' />
</g>
<g id="circGrid6kW">
<line x2='27.7' y2='76.5' x1='-18.9' y1='61.4' style='stroke-width:4px' />
<line x2='26.4' y2='142.5' x1='4.7' y1='155' style='stroke:#222;stroke-width:2;' />
<line x2='82.3' y2='183.1' x1='77.1' y1='207.6' style='stroke:#555;stroke-width:4px;' />
<line x2='149.9' y2='168.8' x1='164.6' y1='189.0' style='stroke:#222;stroke-width:2;' />
<line x2='184.5' y2='108.9' x1='209.4' y1='111.5' style='stroke:#555;stroke-width:4px;' />
<line x2='163.2' y2='43.1' x1='181.7' y1='26.4' style='stroke:#222;stroke-width:2;' />
<line x2='100' y2='24' x1='100' y1='-24' style='stroke-width:4px' />
</g>
<linearGradient id="gradient1" x1="0" x2="0" y1="0" y2="1">
<stop id="tmpH" offset="0%" stop-color="#2389BA" stop-opacity="0.7" />
<stop id="tmpM" offset="50%" stop-color="#2389BA" stop-opacity="0.7" />
<stop id="tmpL" offset="100%" stop-color="#2389BA" stop-opacity="0.7" />
</linearGradient>
<filter id="fillpartialEV" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%">
<feFlood flood-color="#1f5a66" />
<feComposite id="evChargeState" y="100%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" />
</filter>
<filter id="fillpartialHeat" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%">
<feFlood flood-color="#5E2B21" />
<feComposite id="heatChargeState" y="100%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" />
</filter>
<filter id="fillpartialBat" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%">
<feFlood flood-color="#25481C" />
<feComposite id="batChargeState" y="100%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" />
</filter>
<filter id="fillpartialWater" primitiveUnits="objectBoundingBox" x="-5%" y="-5%" width="110%"
height="110%">
<feFlood flood-color="#182C43" />
<feComposite id="waterState" y="50%" operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" />
</filter>
<g id="heater" transform="rotate(-90),scale(0.07,0.07)">
<path
d="M485.924,134.508c14.381,0,26.076-11.669,26.076-26.017v-17.39c0-14.348-11.695-26.017-26.076-26.017H468.61v-8.737
c0-23.89-19.466-43.331-43.39-43.331s-43.39,19.441-43.39,43.331v8.737h-26.034v-8.737c0-23.89-19.466-43.331-43.39-43.331
c-23.924,0-43.39,19.441-43.39,43.331v8.737h-26.034v-8.737c0-23.89-19.466-43.331-43.39-43.331
c-23.924,0-43.39,19.441-43.39,43.331v8.737h-26.034v-8.737c0-23.89-19.466-43.331-43.39-43.331S43.39,32.458,43.39,56.348v8.737
H17.356V39.051H0v34.712v52.068v34.712h17.356v-26.034H43.39v269.017H8.678c-4.797,0-8.678,3.881-8.678,8.678v34.712
c0,4.797,3.881,8.678,8.678,8.678c4.797,0,8.678-3.881,8.678-8.678v-26.034H43.39v34.78c0,23.89,19.466,43.322,43.39,43.322
s43.39-19.432,43.39-43.322v-0.068h26.034v0.068c0,23.89,19.466,43.322,43.39,43.322c23.924,0,43.39-19.432,43.39-43.322v-0.068
h26.034v0.068c0,23.89,19.466,43.322,43.39,43.322c23.924,0,43.39-19.432,43.39-43.322v-0.068h26.034v0.068
c0,23.89,19.466,43.322,43.39,43.322s43.39-19.432,43.39-43.322v-0.068h17.314c14.381,0,26.076-11.669,26.076-26.017v-17.39
c0-14.347-11.695-26.017-26.076-26.017H468.61V134.508H485.924z M468.61,82.441h17.314c4.805,0,8.72,3.881,8.72,8.661v17.39
c0,4.78-3.915,8.661-8.72,8.661H468.61V82.441z M43.39,117.153H17.356V82.441H43.39V117.153z M112.814,73.763v52.068v269.017
v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966V125.831V73.763V56.348
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M156.203,438.237h-26.034v-34.712h26.034V438.237z
M156.203,386.169h-26.034V134.508h26.034V386.169z M156.203,117.153h-26.034V82.441h26.034V117.153z M225.627,73.763v52.068
v269.017v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966v-8.746v-52.068V125.831V73.763V56.348
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M269.017,438.237h-26.034v-34.712h26.034V438.237z
M269.017,386.169h-26.034V134.508h26.034V386.169z M269.017,117.153h-26.034V82.441h26.034V117.153z M338.441,73.763v52.068
v269.017v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966v-8.746v-52.068V125.831V73.763V56.348
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M381.831,438.237h-26.034v-34.712h26.034V438.237z
M381.831,386.169h-26.034V134.508h26.034V386.169z M381.831,117.153h-26.034V82.441h26.034V117.153z M451.254,73.763v52.068
v269.017v52.068v8.746c0,14.313-11.678,25.966-26.034,25.966s-26.034-11.653-26.034-25.966v-8.746v-52.068V125.831V73.763V56.348
c0-14.322,11.678-25.975,26.034-25.975s26.034,11.653,26.034,25.975V73.763z M485.924,403.525c4.805,0,8.72,3.881,8.72,8.661
v17.39c0,4.78-3.915,8.661-8.72,8.661H468.61v-34.712H485.924z" />
</g>
<g id="gas">
<path fill-opacity="1" stroke-width="0.2" stroke-linejoin="round"
d="M 42.75,19L 42.75,31.4977C 44.5834,31.378 48.9184,32.7881 48.2917,49.0833C 49.0833,53.8333 54.625,53.8333 55.8125,47.5C 57,42.75 53.8333,42.75 52.25,28.5C 52.25,26.9167 52.25,22.1667 45.9167,19L 45.9167,17.4167C 52.25,17.4167 57,25.3333 57,26.9167C 57,28.5 55.4167,28.5 55.4167,28.5C 55.4167,28.5 55.8125,38 57.3958,39.5833C 58.9792,41.1667 58.5833,45.9167 58.5833,49.0833C 58.5833,52.25 53.8333,55.4167 52.25,55.4167C 50.6667,55.4167 45.9167,55.4167 45.9167,50.6667C 45.9167,46.3403 45.2599,36.7598 42.75,35.0854L 42.75,55.4167C 43.6244,55.4167 44.3333,56.1255 44.3333,57L 44.3333,60.1667L 19,60.1667L 19,57C 19,56.1255 19.7089,55.4167 20.5833,55.4167L 20.5833,19C 20.5833,17.2511 22.0011,15.8333 23.75,15.8333L 39.5833,15.8333C 41.3322,15.8333 42.75,17.2511 42.75,19 Z M 25.7291,33.2501L 37.6041,33.25C 38.4786,33.25 39.5833,32.1453 39.5833,31.2709L 39.5833,20.9792C 39.5833,20.1048 38.4786,19 37.6041,19L 25.7292,19C 24.8547,19 23.75,20.1048 23.75,20.9792L 23.75,31.2709C 23.75,32.1453 24.8547,33.2501 25.7291,33.2501 Z " />
</g>
<g id="water">
<path
d="M283.897,92.846c-36.582-49.345-73.688-89.267-74.061-89.664C207.944,1.153,205.296,0,202.523,0
c-2.774,0-5.423,1.152-7.314,3.182c-0.371,0.397-37.478,40.319-74.06,89.664c-49.971,67.403-75.308,119.726-75.308,155.513
c0,86.396,70.287,156.688,156.682,156.688c86.396,0,156.683-70.29,156.683-156.688C359.206,212.572,333.868,160.25,283.897,92.846z
M218.171,354.342c-8.213,1.941-16.68,2.926-25.162,2.926c-60.294,0-109.347-49.055-109.347-109.35
c0-8.312,2.559-23.373,14.75-47.914c1.225-2.467,4.046-3.691,6.687-2.908c2.639,0.785,4.33,3.357,4.007,6.091
c-0.28,2.361-0.421,4.584-0.421,6.607c0,64.629,45.966,120.77,109.298,133.484c2.607,0.525,4.5,2.795,4.545,5.455
C222.575,351.396,220.761,353.729,218.171,354.342z" />
</g>
<g id="voltage">
<path stroke="#212529" stroke-width="0.2px" d="M11.46,18V13.58H9.86L12.54,8v3.89h1.6Z" />
</g>
<path id="powerTextPath" d="M 100, 100 m -87, 0 a 87,87 0 1,1 174,0 a 87,87 0 1,1 -174,0"></path>
<path id="infoTextPath" d="M 100, 100 m -105, 0 a 105,105 0 1,0 210,0 a 105,105 0 1,0 -210,0"></path>
<g id="pvPlate" fill="none" stroke-width="4" stroke="#f7c000">
<rect width="70" height="40" x="0" y="0" rx="5" ry="5" />
</g>
<g id="ElementBG">
<path fill="#212529" stroke-width="1.5"
d="M 99.80277789465349 -12.999827891201505 A 113 113 0 1 0 100 -13" />
<path fill="none" stroke-width="4"
d="M 99.86386438745993 22.00011880076356 A 78 78 0 1 0 100 22" />
</g>
<g id="plugIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)" fill="#71afcd">
<path d="M15.21,6.73V2.63A.72.72,0,0,0,14.4,2h0a.71.71,0,0,0-.75.66V6.73Z" />
<path d="M10.39,6.73V2.62A.7.7,0,0,0,9.6,2h0a.73.73,0,0,0-.78.66V6.73Z" />
<path
d="M6.71,7.23C6.37,7.22,6,8,6,8.8V10c0,2.48.57,4.62,1.63,5.28S9,16,10.35,16.77V22h3.3V16.77c1.38-.8,1.66-.85,2.72-1.51S18,12.46,18,10V8.8c0-.78-.37-1.58-.71-1.57Z" />
</g>
<g id="ogIcon" filter="url(#shadow)" transform="translate(52,45),scale(4,4)">
<polygon fill="#70CCBB"
points="12.01 1.5 2 10.32 3.11 10.32 3.11 21.5 5.12 21.5 5.12 10.32 12 4.13 18.89 10.32 18.89 21.5 20.89 21.5 20.89 10.32 22 10.32 12.01 1.5" />
<path fill="#70CCBB"
d="M8.55,12.65v3.49a2.12,2.12,0,0,0,2.13,2.09h.67s0,3.23,0,3.27h1.49s0-3.24,0-3.28h.77a1.82,1.82,0,0,0,1.8-1.85l0-3.73" />
<path fill="#70CCBB" d="M10.76,11.41v-1.3c0-.45-.17-.67-.52-.68s-.54.22-.54.69v1.67h1.06Z" />
<path fill="#70CCBB"
d="M14.3,11.41c0-.44,0-.88,0-1.3s-.17-.67-.51-.68-.55.22-.55.69v1.67H14.3Z" />
<path fill="#212529"
d="M9.86,13.86h4.28a0,0,0,0,1,0,0v2a1,1,0,0,1-1,1H10.86a1,1,0,0,1-1-1v-2A0,0,0,0,1,9.86,13.86Z" />
</g>
<g id="heatIcon" filter="url(#shadow)" transform="translate(52,70),scale(4,4)" fill="#C2614E">
<path clip-path="M-22 2.24h42V22h-42z"
d="M16.543 8.028c-.023 1.503-.523 3.538-2.867 4.327.734-1.746.846-3.417.326-4.979-.695-2.097-3.014-3.735-4.557-4.627-.527-.306-1.203.074-1.193.683.02 1.112-.318 2.737-1.959 4.378C4.107 9.994 3 12.251 3 14.517 3 17.362 5 21 9 21c-4.041-4.041-1-7.483-1-7.483C8.846 19.431 12.988 21 15 21c1.711 0 5-1.25 5-6.448 0-3.133-1.332-5.511-2.385-6.899-.347-.458-1.064-.198-1.072.375" />
</g>
<g id="ugIcon" filter="url(#shadow)" transform="translate(52,50),scale(4,4)">
<rect stroke="#70CC9C" stroke-width="2" fill="none" x="3" y="3" width="18" height="18" rx="2" />
<path fill="#70CC9C"
d="M8.55,9.2v3.47a2.11,2.11,0,0,0,2.13,2.08h.67s0,3.22,0,3.26h1.49s0-3.22,0-3.26h.77a1.81,1.81,0,0,0,1.8-1.84l0-3.71" />
<path fill="#70CC9C" d="M10.76,8V6.67c0-.45-.17-.66-.52-.67s-.54.22-.54.68V8.34h1.06Z" />
<path fill="#70CC9C" d="M14.3,8c0-.44,0-.87,0-1.3S14.12,6,13.78,6s-.55.22-.55.68V8.34H14.3Z" />
<path fill="#212529"
d="M9.86,10.41h4.28a0,0,0,0,1,0,0v2a1,1,0,0,1-1,1H10.86a1,1,0,0,1-1-1v-2A0,0,0,0,1,9.86,10.41Z" />
</g>
<g id="carIcon" filter="url(#shadow)" transform="translate(45,45),scale(4.8,4.8)"
fill="#212529" stroke-linecap="round">
<path d="M16.22,15.37l-9.3-.16L3,15,.88,14.47.75,10.39A2.78,2.78,0,0,1,1.31,9.2L2.55,7.63" />
<path
d="M.78,7.46,7,7l.87,0L11.37,7a5.57,5.57,0,0,1,1.06.23,9.43,9.43,0,0,1,2.16,1L17.23,9.9l4.22.7a1.73,1.73,0,0,1,1.21.93l.26.49a2.84,2.84,0,0,1,.32,1.6l0,.23A1.52,1.52,0,0,1,22.53,15h0a1.53,1.53,0,0,1-.56.21l-.89.15H15.59" />
<path fill="#888888" stroke="none"
d="M16.06,11c-1.85.11-3.7.14-5.55.16a13.36,13.36,0,0,1-2.82,0,2.62,2.62,0,0,1-.87-.4,1.28,1.28,0,0,1-.53-1.05,1.4,1.4,0,0,1,.09-.51,2.67,2.67,0,0,1,.22-.35,2.79,2.79,0,0,1,.5-.58s.09,0,.11,0a.06.06,0,0,1,0,.05h0c0,.25,0,.49,0,.71s0,.23,0,.31a.75.75,0,0,0,.08.18c.07.09.17.14.17.08a1.81,1.81,0,0,0,.43.05,14.41,14.41,0,0,1,2.68.33c1.82.26,3.64.53,5.46.88a.08.08,0,0,1,.06.09A.07.07,0,0,1,16.06,11Z" />
<circle cx="4.94" cy="15.08" r="1.98" />
<circle cx="19.19" cy="15.08" r="1.98" />
</g>
<g id="plugCordIcon" transform="scale(0.08,0.08),rotate(340),translate(-350,1200)">
<path
d="M489.8,280.92c0-13.9-11.3-25.2-25.2-25.2h-74.1c-62.1,0-112.4,50.2-112.7,112.2c-0.1,32.3-23,61-55,65
c-38.4,4.8-71.2-25.2-71.2-62.6v-56.4c57.6-11.7,101-62.6,101-123.7v-64c0-9.1-7.3-16.4-16.4-16.4h-31.3v-79.1
c0-12.4-9-23.4-21.3-24.6c-14.1-1.4-26,9.7-26,23.6v80.1H95.2v-79.1c0-12.4-9-23.4-21.4-24.6c-14.1-1.3-26,9.7-26,23.6v80.1H16.4
c-9.1,0-16.4,7.3-16.4,16.4v64c0,61.1,43.4,112,101,123.7v53.5c0,61.5,47.7,114,109.2,116.3c64.6,2.4,118-49.4,118-113.5v-0.9
c0-34.9,28.3-63.1,63.1-63.1h73.2C478.5,306.12,489.8,294.82,489.8,280.92L489.8,280.92z" />
</g>
<g id="lockIcon" transform="translate(80,130),scale(0.11,0.11)" style="">
<path
d="M65,330h200c8.284,0,15-6.716,15-15V145c0-8.284-6.716-15-15-15h-15V85c0-46.869-38.131-85-85-85
S80,38.131,80,85v45H65c-8.284,0-15,6.716-15,15v170C50,323.284,56.716,330,65,330z M207.481,219.356l-42.5,42.5
c-2.929,2.929-6.768,4.394-10.606,4.394s-7.678-1.465-10.606-4.394l-21.25-21.25c-5.858-5.858-5.858-15.354,0-21.213
c5.857-5.858,15.355-5.858,21.213,0l10.644,10.643l31.894-31.893c5.857-5.858,15.355-5.858,21.213,0
C213.34,204.002,213.34,213.498,207.481,219.356z M110,85c0-30.327,24.673-55,55-55s55,24.673,55,55v45H110V85z"
style="stroke-width:15px;stroke:rgb(30,30,40);fill:#778;" />
</g>
<g filter="url(#shadow)" id="clock" style="fill:#cc0;"
transform="translate(80,32),scale(0.07,0.07)">
<path
d="m256,51.8c-112.6,0-204.2,91.6-204.2,204.2s91.6,204.2 204.2,204.2 204.2-91.6 204.2-204.2-91.6-204.2-204.2-204.2v-1.42109e-14zm0,449.2c-135.1,0-245-109.9-245-245s109.9-245 245-245 245,109.9 245,245-109.9,245-245,245z" />
<path
d="m327.9,276.4h-71.9c-11.3,0-20.4-9.1-20.4-20.4v-132.2c0-11.3 9.1-20.4 20.4-20.4 11.3,0 20.4,9.1 20.4,20.4v111.8h51.5c11.3,0 20.4,9.1 20.4,20.4s-9.1,20.4-20.4,20.4z" />
</g>
<g id="sunIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)"
style="stroke:#f7c000;stroke-width:2;stroke-linecap:round;">
<path id="Pfad_7565" data-name="Pfad 7565" fill="#f7c002" stroke-width="0"
d="M12,8a4,4,0,1,0,4,4A4,4,0,0,0,12,8Z" />
<line x1="12" y1="3" x2="12" y2="5" />
<line x1="12" y1="19" x2="12" y2="21" />
<line x1="19" y1="12" x2="21" y2="12" />
<line x1="3" y1="12" x2="5" y2="12" />
<line x1="5.7" y1="18.5" x2="7" y2="17" />
<line x1="5.7" y1="5.7" x2="7" y2="7" />
<line x1="18.5" y1="18.5" x2="16.7" y2="17" />
<line x1="18.5" y1="5.7" x2="16.7" y2="7" />
</g>
<g id="battIcon" filter="url(#shadow)" transform="translate(30,25),scale(6,6)">
<g>
<rect fill="#6cbe58" x="9.25" y="3" width="5.5" height="4" rx="1" ry="1" />
<path fill="#6cbe58"
d="M16.28,5H7.72A1.21,1.21,0,0,0,6.5,6.2V19.73A1.28,1.28,0,0,0,7.72,21h8.56a1.28,1.28,0,0,0,1.22-1.27V6.2A1.21,1.21,0,0,0,16.28,5Z" />
<rect id="discharged" fill="#212529" rx="1" ry="1" x="8" y="6.5" width="8"
height="13" />
<use id="charge" fill="#cccc00" href="#voltage" />
</g>
</g>
<g id="gridIcon" filter="url(#shadow)" transform="translate(30,27),scale(6,6)">
<path fill="#808090"
d="M13.38,8.54V6.63H18.3V8.06h.95V5.7l-6.35-1L12,2l-1,2.8-6.25.9V8.07H5.6V6.63h4.84V8.54l-7.59,1.9v2.84H3.8V11.76H9.87L6.93,22H9.11l.57-2.46h4.59L14.8,22h2.27L14.13,11.76H20.2v1.52h.95V10.44Zm-3.32,8.81L12,11.11l1.91,6.24Z" />
</g>
<g id="inverterIcon" filter="url(#shadowBig)" fill="#b2b2b2" stroke-width="2px" stroke="#666"
transform="translate(43,43),scale(1.6,1.6)">
<rect stroke-width="2px" x="5.65" y="3" width="58.7" height="64" rx="6.8" />
<circle cx="35.03" cy="29.61" r="11" />
<circle cx="15" cy="40" r="4" />
<path
d="M40.19,52H36.73a2,2,0,0,0-3.46,0H29.81a1.08,1.08,0,1,0,0,2.15h3.46a2,2,0,0,0,3.46,0h3.46a1.08,1.08,0,1,0,0-2.15Z" />
<path fill="#e2001a"
d="M34.89,61.87c-3.24,0-5.87-.73-5.87-1.62s2.63-1.64,5.87-1.64,5.87.74,5.87,1.64S38.13,61.87,34.89,61.87Z" />
<line x1="5.07" y1="53.08" x2="28.73" y2="53.08" />
<line x1="41.27" y1="53.08" x2="64.93" y2="53.08" />
</g>
<g id="northIcon" fill="#808090">
<path
d="M42.066 0v20h3.752V6.957L53.881 20h4.053V0h-3.752v13.355L45.996 0zm5.57 26.688l-25.77 69.949c-.823 2.238 1.658 4.248 3.677 2.978L50 84.195l24.455 15.42c2.02 1.273 4.504-.738 3.68-2.978l-25.79-70c-.472-1.096-1.283-1.632-2.384-1.635c-1.1-.003-2.017.856-2.324 1.686zm-.136 14.83V79.86L29.1 91.463z"></path>
</g>
<g filter="url(#shadow)" id="ecoIcon" transform="translate(60,12)">
<path style="stroke:#6cbe58;fill:rgb(30,30,40);" stroke-width="3" stroke-linejoin="round"
d="M 57,22.1667C 49.0833,28.5 52.25,31.6667 50.6667,36.4167C 49.0833,41.1667 50.6667,42.75 44.3333,47.5C 36.2227,53.583 29.2917,49.875 29.2917,49.875C 27.7083,51.4583 21.7708,54.2292 21.7708,54.2292L 20.0143,50.7285C 26.3476,49.1452 27.7083,47.1042 27.7083,47.1042C 26.125,43.9375 23.75,38 28.5,30.0833C 33.25,22.1667 57,22.1667 57,22.1667 Z M 30.0833,44.3333L 31.6667,45.9167C 31.6667,45.9167 34.8333,44.3333 36.4167,39.5833C 38,34.8333 45.9167,26.9167 45.9167,26.9167C 42.75,28.5 36.4167,34.8333 34.8333,39.5833C 33.25,44.3333 30.0833,44.3333 30.0833,44.3333 Z " />
</g>
<g filter="url(#shadow)" id="alertIcon" fill="#aa0" transform="translate(34,28),scale(2.2,2.2)">
<path
d="M214.413,746a4.455,4.455,0,0,1-3.84-2.166,4.249,4.249,0,0,1,0-4.334l25.572-43.331a4.483,4.483,0,0,1,7.679,0L269.4,739.5a4.249,4.249,0,0,1,0,4.334,4.452,4.452,0,0,1-3.84,2.166H214.413ZM240,706a4,4,0,0,0-4,4v16a4,4,0,0,0,8,0V710A4,4,0,0,0,240,706Zm0,36a4,4,0,1,0-4-4A4,4,0,0,0,240,742Z"
id="attention" transform="translate(-209.969 -694)" />
</g>
</defs>
<g id="pvDetail" opacity="1" transform="scale(1,1)">
<g id="pvInfo" transform="translate(80,30)" class="clickable" onclick="displayOverlay('realtime')">
<!--<g
filter="url(#glow)">-->
<use href="#ElementBG" stroke="#574400" />
<use href="#sunIcon" />
<path id="pvArc" fill="none" stroke="#f7c000" stroke-width="30" />
<path id="pv2Arc" fill="none" stroke="#f78d00" stroke-width="30" />
<path id="pv3Arc" fill="none" stroke="#f72300" stroke-width="30" />
<use href="#circGrid" style="stroke:#574400;" />
<!--</g>-->
<text filter="url(#shadowMiddle)" class="powerTextClass">
<textPath id="pvText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
<textPath id="pv3txt" href="#infoTextPath" startOffset="12%">--.-- kW</textPath>
<textPath id="pv2txt" href="#infoTextPath" startOffset="35%">--.-- kW</textPath>
<textPath id="pv1txt" href="#infoTextPath" startOffset="55%">--W</textPath>
</text>
</g>
<animate begin="openDetails.begin" attributetype="CSS" attributeName="opacity" from="0"
to="1.0"
dur="0.7s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze" />
<animateTransform attributeName="transform"
type="scale"
from="0.1,0.1"
to="1,1"
begin="openDetails.begin"
dur="0.3s" repeatCount="1" fill="freeze" />
<animate begin="closeDetails.click" attributetype="CSS" attributeName="opacity" from="1.0"
to="0"
dur="0.4s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze" />
<animateTransform attributeName="transform"
type="scale"
from="1,1"
to="0.1,0.1"
begin="closeDetails.click"
dur="0.7s" repeatCount="1" fill="freeze" />
<use href="#northIcon" transform="translate(1200,10),rotate(10)" />
<polygon points="370 0, 1300 0, 1300 700, 0 700, 0 250, 370 250" fill="rgb(24, 27, 31)" />
<polygon points="560,80 720,80 720,300 1160,300 1160,370 560,370" stroke-linejoin="round"
fill="#f7c002" stroke-width="30" stroke="#f7c002" opacity="0.1" />
<use href="#pvPlate" transform="translate(600,80), rotate(90)" />
<use href="#pvPlate" transform="translate(600,150), rotate(90)" />
<use href="#pvPlate" transform="translate(600,220), rotate(90)" />
<use href="#pvPlate" transform="translate(600,290), rotate(90)" />
<use href="#pvPlate" transform="translate(640,80), rotate(90)" />
<use href="#pvPlate" transform="translate(640,150), rotate(90)" />
<use href="#pvPlate" transform="translate(640,220), rotate(90)" />
<use href="#pvPlate" transform="translate(640,290), rotate(90)" />
<use href="#pvPlate" transform="translate(680,80), rotate(90)" />
<use href="#pvPlate" transform="translate(680,150), rotate(90)" />
<use href="#pvPlate" transform="translate(680,220), rotate(90)" />
<use href="#pvPlate" transform="translate(680,290), rotate(90)" />
<use href="#pvPlate" transform="translate(720,80), rotate(90)" />
<use href="#pvPlate" transform="translate(720,150), rotate(90)" />
<use href="#pvPlate" transform="translate(720,220), rotate(90)" />
<use href="#pvPlate" transform="translate(790,290)" />
<use href="#pvPlate" transform="translate(720,330)" />
<use href="#pvPlate" transform="translate(790,330)" />
<use href="#pvPlate" transform="translate(870,290)" />
<use href="#pvPlate" transform="translate(870,330)" />
<use href="#pvPlate" transform="translate(940,330)" />
<use href="#pvPlate" transform="translate(1160,300), rotate(90)" />
<use href="#pvPlate" transform="translate(1120,300), rotate(90)" />
<use href="#pvPlate" transform="translate(1080,300), rotate(90)" />
<text id="det_pv0P" filter="url(#shadowBig)" class="infoTextClass" dx="55" dy="30"
transform="translate(560, 150), scale(1.5,1.5)">-.-- kW</text>
<polygon points="980,60 1160,60 1160,265 980,265" stroke-linejoin="round" fill="#F76D00"
stroke-width="30" stroke="#F76D00" opacity="0.1" />
<use href="#pvPlate" transform="translate(1160,200), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1115,200), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1070,200), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1160,130), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1115,130), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1070,130), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1025,130), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1160,60), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1115,60), rotate(90), scale(1,1.125)" />
<use href="#pvPlate" transform="translate(1070,60), rotate(90), scale(1,1.125)" />
<text id="det_pv1P" filter="url(#shadowBig)" class="infoTextClass" dx="55" dy="30"
transform="translate(990, 140), scale(1.5,1.5)">-.-- kW</text>
<use href="#pvPlate" x="200" y="680" />
<text id="det_pv33P" filter="url(#shadowMiddle)" class="infoTextClass" x="200" y="680"
dx="36"
dy="26">#19</text>
<use href="#pvPlate" x="380" y="550" />
<text id="det_pv32P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="550"
dx="36"
dy="26">#19</text>
<use href="#pvPlate" x="380" y="590" />
<text id="det_pv31P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="590"
dx="36"
dy="26">#18</text>
<use href="#pvPlate" x="380" y="630" />
<text id="det_pv30P" filter="url(#shadowMiddle)" class="infoTextClass" x="380" y="630"
dx="36"
dy="26">#17</text>
<use href="#pvPlate" x="310" y="510" />
<text id="det_pv29P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="510"
dx="36"
dy="26">#16</text>
<use href="#pvPlate" x="310" y="550" />
<text id="det_pv28P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="550"
dx="36"
dy="26">#15</text>
<use href="#pvPlate" x="310" y="590" />
<text id="det_pv27P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="590"
dx="36"
dy="26">#14</text>
<use href="#pvPlate" x="310" y="630" />
<text id="det_pv26P" filter="url(#shadowMiddle)" class="infoTextClass" x="310" y="630"
dx="36"
dy="26">#13</text>
<use href="#pvPlate" x="240" y="510" />
<text id="det_pv25P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="510"
dx="36"
dy="26">#12</text>
<use href="#pvPlate" x="240" y="550" />
<text id="det_pv24P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="550"
dx="36"
dy="26">#11</text>
<use href="#pvPlate" x="240" y="590" />
<text id="det_pv23P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="590"
dx="36"
dy="26">#10</text>
<use href="#pvPlate" x="240" y="630" />
<text id="det_pv22P" filter="url(#shadowMiddle)" class="infoTextClass" x="240" y="630"
dx="36"
dy="26">#9</text>
<use href="#pvPlate" x="170" y="510" />
<text id="det_pv21P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="510"
dx="36"
dy="26">#8</text>
<use href="#pvPlate" x="170" y="550" />
<text id="det_pv20P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="550"
dx="36"
dy="26">#7</text>
<use href="#pvPlate" x="170" y="590" />
<text id="det_pv19P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="590"
dx="36"
dy="26">#6</text>
<use href="#pvPlate" x="170" y="630" />
<text id="det_pv18P" filter="url(#shadowMiddle)" class="infoTextClass" x="170" y="630"
dx="36"
dy="26">#5</text>
<use href="#pvPlate" x="100" y="510" />
<text id="det_pv14P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="510"
dx="36"
dy="26">#1</text>
<use href="#pvPlate" x="100" y="550" />
<text id="det_pv15P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="550"
dx="36"
dy="26">#2</text>
<use href="#pvPlate" x="100" y="590" />
<text id="det_pv16P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="590"
dx="36"
dy="26">#3</text>
<use href="#pvPlate" x="100" y="630" />
<text id="det_pv17P" filter="url(#shadowMiddle)" class="infoTextClass" x="100" y="630"
dx="36"
dy="26">#4</text>
<use href="#pvPlate" transform="translate(600,500)" />
<text id="det_pv13P" filter="url(#shadowMiddle)" class="infoTextClass" x="600" y="500"
dx="36"
dy="26">- W</text>
<use href="#pvPlate" transform="translate(500,500)" />
<text id="det_pv12P" filter="url(#shadowMiddle)" class="infoTextClass" x="500" y="500"
dx="36"
dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,120), rotate(-90)" />
<text id="det_pv5P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,120), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,190), rotate(-90)" />
<text id="det_pv4P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,190), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,270), rotate(-90)" />
<text id="det_pv9P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,270), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,340), rotate(-90)" />
<text id="det_pv8P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,340), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,420), rotate(-90)" />
<text id="det_pv11P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,420), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(460,490), rotate(-90)" />
<text id="det_pv10P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(460,490), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,120), rotate(-90)" />
<text id="det_pv7P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,120), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,190), rotate(-90)" />
<text id="det_pv6P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,190), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,270), rotate(-90)" />
<text id="det_pv3P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,270), rotate(-90)" dx="36" dy="26">- W</text>
<use href="#pvPlate" transform="translate(400,340), rotate(-90)" />
<text id="det_pv2P" filter="url(#shadowMiddle)" class="infoTextClass"
transform="translate(400,340), rotate(-90)" dx="36" dy="26">- W</text>
<text id="invList" filter="url(#shadowMiddle)" class="tooltipTextClass"
transform="translate(80,255)"></text>
<rect width="305" height="210" x="70" y="250" rx="5" ry="5" fill="none" stroke-width="4px"
stroke="#f7c000" />
</g>
</svg>

Before

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

View File

@ -1,52 +1,52 @@
<?php
session_start();
require_once("restricted/mysql.php");
$_SESSION["local"] =false;
function isLocal(){
$ipv6_prefix = explode(":",$_SERVER['SERVER_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.")){
$_SESSION["local"] =true;
return true;
}else{
return false;
}
}
function checkLogin(){
$mysql = new mysqli($GLOBALS["mysql_server"],$GLOBALS["mysql_user"],$GLOBALS["mysql_pass"],$GLOBALS["mysql_db"]);
if(isLocal()){
$_SESSION["local"] =true;
return true;
}
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"])."';");
if(!$res){
echo mysqli_error($mysql);
return false;
}
if(mysqli_num_rows($res) == 1){
return isset($_SESSION["Logged"]);
}
}else{
return false;
}
}
function checkAdduser(){
$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);")){
echo mysqli_error($mysql);
}
$result = mysqli_query($mysql,"SELECT * FROM addUser WHERE accesskey='".mysqli_real_escape_string($mysql,$_GET["addUser"])."';");
if(!$result){
return false;
}
if ($result->num_rows > 0) {
return true;
}
return false;
}
<?php
session_start();
require_once("restricted/mysql.php");
$_SESSION["local"] =false;
function isLocal(){
$ipv6_prefix = explode(":",$_SERVER['SERVER_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.")){
$_SESSION["local"] =true;
return true;
}else{
return false;
}
}
function checkLogin(){
$mysql = new mysqli($GLOBALS["mysql_server"],$GLOBALS["mysql_user"],$GLOBALS["mysql_pass"],$GLOBALS["mysql_db"]);
if(isLocal()){
$_SESSION["local"] =true;
return true;
}
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"])."';");
if(!$res){
echo mysqli_error($mysql);
return false;
}
if(mysqli_num_rows($res) == 1){
return isset($_SESSION["Logged"]);
}
}else{
return false;
}
}
function checkAdduser(){
$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);")){
echo mysqli_error($mysql);
}
$result = mysqli_query($mysql,"SELECT * FROM addUser WHERE accesskey='".mysqli_real_escape_string($mysql,$_GET["addUser"])."';");
if(!$result){
return false;
}
if ($result->num_rows > 0) {
return true;
}
return false;
}
?>

286
index.php
View File

@ -1,143 +1,143 @@
<?php
require_once("helper.php");
if (isset($_GET["addUser"])) {
if (checkAdduser($_GET["addUser"])) {
echo <<<ENDE
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Smarthome control</title>
<link rel="icon" type="image/png" href="assets/img/favicon.png">
<!--end::Accessibility Meta Tags-->
<!--begin::Primary Meta Tags-->
<meta name="title" content="Smarthome control" />
<meta name="author" content="ColorlibHQ" />
<meta name="description" content="Smarthome control panel by m0." />
<meta name="keywords" content="smarthome dashboard, admin panel" />
<!--end::Primary Meta Tags-->
<!--begin::Fonts-->
<link rel="stylesheet" href="assets/fonts/font_poppins.css" media="print" onload="this.media='all'" />
<!--end::Fonts-->
<!--begin::Third Party Plugin(OverlayScrollbars)
<link rel="stylesheet" href="css/overlayscrollbars.min.css" />-->
<!--end::Third Party Plugin(OverlayScrollbars)-->
<!--begin::Third Party Plugin(Bootstrap Icons)-->
<link rel="stylesheet" href="css/bootstrap-icons.min.css" />
<!--end::Third Party Plugin(Bootstrap Icons)-->
<!--begin::Required Plugin(AdminLTE)-->
<link rel="stylesheet" href="./css/adminlte.css?v=2" />
<!--end::Required Plugin(AdminLTE)-->
</head>
<body onload="createRegistration()">
</body>
<script src="js/auth.js"></script>
<script>
async function createRegistration() {
try {
// check browser support
if (!window.fetch || !navigator.credentials || !navigator.credentials.create) {
throw new Error('Browser not supported.');
}
let keyName = encodeURIComponent(prompt('Bitte Hier den Namen des Schlüssels eingeben:'));
// get create args
let rep = await window.fetch('authServer.php?fn=getCreateArgs', {method:'GET', cache:'no-cache'});
//alert(await rep.text());
const createArgs = await rep.json();
// error handling
if (createArgs.success === false) {
throw new Error(createArgs.msg || 'unknown error occured');
}
// replace binary base64 data with ArrayBuffer. a other way to do this
// is the reviver function of JSON.parse()
recursiveBase64StrToArrayBuffer(createArgs);
// create credentials
const cred = await navigator.credentials.create(createArgs);
// create object
const authenticatorAttestationResponse = {
transports: cred.response.getTransports ? cred.response.getTransports() : null,
clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
attestationObject: cred.response.attestationObject ? arrayBufferToBase64(cred.response.attestationObject) : null
};
// check auth on server side
rep = await window.fetch('authServer.php?fn=processCreate&name='+keyName, {
method : 'POST',
body : JSON.stringify(authenticatorAttestationResponse),
cache : 'no-cache'
});
authenticatorAttestationServerResponse = await rep.json();
// prompt server response
if (authenticatorAttestationServerResponse.success) {
window.alert(authenticatorAttestationServerResponse.msg || 'registration success');
if(!authenticatorAttestationServerResponse.msg){
window.location.href = "https://nas.el-wa.org/smart";
}
} else {
throw new Error(authenticatorAttestationServerResponse.msg);
}
} catch (err) {
window.alert(err.message || 'unknown error occured');
}
}
</script>
</html>
ENDE;
}
} else if (checkLogin()) {
include "restricted/header.php";
if(!isset($_GET["action"])){
$_GET["action"] = "solar";
}
$resource_content = "";
switch($_GET["action"]){
case "solar":
$resource_content .= str_replace("%%INSERTSVG%%", file_get_contents('assets/img/realtime.svg'), file_get_contents('restricted/solar.html'));
$resource_content .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/solarMQTT.js'></script>";
break;
case "home":
include "restricted/home.php";
$resource_content .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/autoActionFuncs.js'></script>";
$resource_content .= "<script src='js/solar/homeMQTT.js'></script>";
break;
case "heat":
$resource_content .= file_get_contents('restricted/heat.html');
$resource_content .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/heatMQTT.js'></script>";
break;
case "history":
$resource_content .= file_get_contents('restricted/history.html');
$resource_content .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/historyMQTT.js'></script>";
break;
}
echo $resource_content;
} else {
echo <<<ENDE
<html>
<head><link rel="icon" type="image/png" href="assets/img/favicon.png"></head>
<body onload="checkRegistration()">
<script src="js/auth.js"></script>
</body>
</html>
ENDE;
}
<?php
require_once("helper.php");
if (isset($_GET["addUser"])) {
if (checkAdduser($_GET["addUser"])) {
echo <<<ENDE
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Smarthome control</title>
<link rel="icon" type="image/png" href="assets/img/favicon.png">
<!--end::Accessibility Meta Tags-->
<!--begin::Primary Meta Tags-->
<meta name="title" content="Smarthome control" />
<meta name="author" content="ColorlibHQ" />
<meta name="description" content="Smarthome control panel by m0." />
<meta name="keywords" content="smarthome dashboard, admin panel" />
<!--end::Primary Meta Tags-->
<!--begin::Fonts-->
<link rel="stylesheet" href="assets/fonts/font_poppins.css" media="print" onload="this.media='all'" />
<!--end::Fonts-->
<!--begin::Third Party Plugin(OverlayScrollbars)
<link rel="stylesheet" href="css/overlayscrollbars.min.css" />-->
<!--end::Third Party Plugin(OverlayScrollbars)-->
<!--begin::Third Party Plugin(Bootstrap Icons)-->
<link rel="stylesheet" href="css/bootstrap-icons.min.css" />
<!--end::Third Party Plugin(Bootstrap Icons)-->
<!--begin::Required Plugin(AdminLTE)-->
<link rel="stylesheet" href="./css/adminlte.css?v=2" />
<!--end::Required Plugin(AdminLTE)-->
</head>
<body onload="createRegistration()">
</body>
<script src="js/auth.js"></script>
<script>
async function createRegistration() {
try {
// check browser support
if (!window.fetch || !navigator.credentials || !navigator.credentials.create) {
throw new Error('Browser not supported.');
}
let keyName = encodeURIComponent(prompt('Bitte Hier den Namen des Schlüssels eingeben:'));
// get create args
let rep = await window.fetch('authServer.php?fn=getCreateArgs', {method:'GET', cache:'no-cache'});
//alert(await rep.text());
const createArgs = await rep.json();
// error handling
if (createArgs.success === false) {
throw new Error(createArgs.msg || 'unknown error occured');
}
// replace binary base64 data with ArrayBuffer. a other way to do this
// is the reviver function of JSON.parse()
recursiveBase64StrToArrayBuffer(createArgs);
// create credentials
const cred = await navigator.credentials.create(createArgs);
// create object
const authenticatorAttestationResponse = {
transports: cred.response.getTransports ? cred.response.getTransports() : null,
clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
attestationObject: cred.response.attestationObject ? arrayBufferToBase64(cred.response.attestationObject) : null
};
// check auth on server side
rep = await window.fetch('authServer.php?fn=processCreate&name='+keyName, {
method : 'POST',
body : JSON.stringify(authenticatorAttestationResponse),
cache : 'no-cache'
});
authenticatorAttestationServerResponse = await rep.json();
// prompt server response
if (authenticatorAttestationServerResponse.success) {
window.alert(authenticatorAttestationServerResponse.msg || 'registration success');
if(!authenticatorAttestationServerResponse.msg){
window.location.href = "https://nas.el-wa.org/smart";
}
} else {
throw new Error(authenticatorAttestationServerResponse.msg);
}
} catch (err) {
window.alert(err.message || 'unknown error occured');
}
}
</script>
</html>
ENDE;
}
} else if (checkLogin()) {
include "restricted/header.php";
if(!isset($_GET["action"])){
$_GET["action"] = "solar";
}
$resource_content = "";
switch($_GET["action"]){
case "solar":
$resource_content .= str_replace("%%INSERTSVG%%", file_get_contents('assets/img/realtime.svg'), file_get_contents('restricted/solar.html'));
$resource_content .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/solarMQTT.js'></script>";
break;
case "home":
include "restricted/home.php";
$resource_content .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/autoActionFuncs.js'></script>";
$resource_content .= "<script src='js/solar/homeMQTT.js'></script>";
break;
case "heat":
$resource_content .= file_get_contents('restricted/heat.html');
$resource_content .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/heatMQTT.js'></script>";
break;
case "history":
$resource_content .= file_get_contents('restricted/history.html');
$resource_content .= file_get_contents('restricted/footer.html');
$resource_content .= "<script src='js/solar/historyMQTT.js'></script>";
break;
}
echo $resource_content;
} else {
echo <<<ENDE
<html>
<head><link rel="icon" type="image/png" href="assets/img/favicon.png"></head>
<body onload="checkRegistration()">
<script src="js/auth.js"></script>
</body>
</html>
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() {
try {
if (!window.fetch || !navigator.credentials || !navigator.credentials.create) {
throw new Error('Browser not supported.');
}
// get check args
let rep = await window.fetch('authServer.php?fn=getGetArgs' + getGetParams(), {method:'GET',cache:'no-cache'});
const getArgs = await rep.json();
// error handling
if (getArgs.success === false) {
throw new Error(getArgs.msg);
}
// replace binary base64 data with ArrayBuffer. a other way to do this
// is the reviver function of JSON.parse()
recursiveBase64StrToArrayBuffer(getArgs);
// check credentials with hardware
const cred = await navigator.credentials.get(getArgs);
// create object for transmission to server
const authenticatorAttestationResponse = {
id: cred.rawId ? arrayBufferToBase64(cred.rawId) : null,
clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
authenticatorData: cred.response.authenticatorData ? arrayBufferToBase64(cred.response.authenticatorData) : null,
signature: cred.response.signature ? arrayBufferToBase64(cred.response.signature) : null,
userHandle: cred.response.userHandle ? arrayBufferToBase64(cred.response.userHandle) : null
};
// send to server
rep = await window.fetch('authServer.php?fn=processGet' + getGetParams(), {
method:'POST',
body: JSON.stringify(authenticatorAttestationResponse),
cache:'no-cache'
});
const authenticatorAttestationServerResponse = await rep.json();
// check server response
if (authenticatorAttestationServerResponse.success) {
window.location.reload();
/// window.alert(authenticatorAttestationServerResponse.msg || 'login success');
} else {
throw new Error(authenticatorAttestationServerResponse.msg);
}
} catch (err) {
//reloadServerPreview();
window.alert(err.message || 'unknown error occured');
}
}
function queryFidoMetaDataService() {
window.fetch('authServer.php?fn=queryFidoMetaDataService' + getGetParams(), {method:'GET',cache:'no-cache'}).then(function(response) {
return response.json();
}).then(function(json) {
if (json.success) {
window.alert(json.msg);
} else {
throw new Error(json.msg);
}
}).catch(function(err) {
window.alert(err.message || 'unknown error occured');
});
}
/**
* convert RFC 1342-like base64 strings to array buffer
* @param {mixed} obj
* @returns {undefined}
*/
function recursiveBase64StrToArrayBuffer(obj) {
let prefix = '=?BINARY?B?';
let suffix = '?=';
if (typeof obj === 'object') {
for (let key in obj) {
if (typeof obj[key] === 'string') {
let str = obj[key];
if (str.substring(0, prefix.length) === prefix && str.substring(str.length - suffix.length) === suffix) {
str = str.substring(prefix.length, str.length - suffix.length);
let binary_string = window.atob(str);
let len = binary_string.length;
let bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
obj[key] = bytes.buffer;
}
} else {
recursiveBase64StrToArrayBuffer(obj[key]);
}
}
}
}
/**
* Convert a ArrayBuffer to Base64
* @param {ArrayBuffer} buffer
* @returns {String}
*/
function arrayBufferToBase64(buffer) {
let binary = '';
let bytes = new Uint8Array(buffer);
let len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa(binary);
}
/**
* Get URL parameter
* @returns {String}
*/
function getGetParams() {
let url = '';
url += '&apple=1';
url += '&yubico=1';
url += '&solo=1';
url += '&hypersecu=1';
url += '&google=1';
url += '&microsoft=1';
url += '&mds=1';
url += '&requireResidentKey=0';
url += '&type_usb=1';
url += '&type_nfc=1';
url += '&type_ble=1';
url += '&type_int=1';
url += '&type_hybrid=1';
url += '&fmt_android-key=1';
url += '&fmt_android-safetynet=1';
url += '&fmt_apple=1';
url += '&fmt_fido-u2f=1';
url += '&fmt_none=0' ;
url += '&fmt_packed=1';
url += '&fmt_tpm=1';
url += '&userVerification=discouraged';
return url;
async function checkRegistration() {
try {
if (!window.fetch || !navigator.credentials || !navigator.credentials.create) {
throw new Error('Browser not supported.');
}
// get check args
let rep = await window.fetch('authServer.php?fn=getGetArgs' + getGetParams(), {method:'GET',cache:'no-cache'});
const getArgs = await rep.json();
// error handling
if (getArgs.success === false) {
throw new Error(getArgs.msg);
}
// replace binary base64 data with ArrayBuffer. a other way to do this
// is the reviver function of JSON.parse()
recursiveBase64StrToArrayBuffer(getArgs);
// check credentials with hardware
const cred = await navigator.credentials.get(getArgs);
// create object for transmission to server
const authenticatorAttestationResponse = {
id: cred.rawId ? arrayBufferToBase64(cred.rawId) : null,
clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
authenticatorData: cred.response.authenticatorData ? arrayBufferToBase64(cred.response.authenticatorData) : null,
signature: cred.response.signature ? arrayBufferToBase64(cred.response.signature) : null,
userHandle: cred.response.userHandle ? arrayBufferToBase64(cred.response.userHandle) : null
};
// send to server
rep = await window.fetch('authServer.php?fn=processGet' + getGetParams(), {
method:'POST',
body: JSON.stringify(authenticatorAttestationResponse),
cache:'no-cache'
});
const authenticatorAttestationServerResponse = await rep.json();
// check server response
if (authenticatorAttestationServerResponse.success) {
window.location.reload();
/// window.alert(authenticatorAttestationServerResponse.msg || 'login success');
} else {
throw new Error(authenticatorAttestationServerResponse.msg);
}
} catch (err) {
//reloadServerPreview();
window.alert(err.message || 'unknown error occured');
}
}
function queryFidoMetaDataService() {
window.fetch('authServer.php?fn=queryFidoMetaDataService' + getGetParams(), {method:'GET',cache:'no-cache'}).then(function(response) {
return response.json();
}).then(function(json) {
if (json.success) {
window.alert(json.msg);
} else {
throw new Error(json.msg);
}
}).catch(function(err) {
window.alert(err.message || 'unknown error occured');
});
}
/**
* convert RFC 1342-like base64 strings to array buffer
* @param {mixed} obj
* @returns {undefined}
*/
function recursiveBase64StrToArrayBuffer(obj) {
let prefix = '=?BINARY?B?';
let suffix = '?=';
if (typeof obj === 'object') {
for (let key in obj) {
if (typeof obj[key] === 'string') {
let str = obj[key];
if (str.substring(0, prefix.length) === prefix && str.substring(str.length - suffix.length) === suffix) {
str = str.substring(prefix.length, str.length - suffix.length);
let binary_string = window.atob(str);
let len = binary_string.length;
let bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
obj[key] = bytes.buffer;
}
} else {
recursiveBase64StrToArrayBuffer(obj[key]);
}
}
}
}
/**
* Convert a ArrayBuffer to Base64
* @param {ArrayBuffer} buffer
* @returns {String}
*/
function arrayBufferToBase64(buffer) {
let binary = '';
let bytes = new Uint8Array(buffer);
let len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa(binary);
}
/**
* Get URL parameter
* @returns {String}
*/
function getGetParams() {
let url = '';
url += '&apple=1';
url += '&yubico=1';
url += '&solo=1';
url += '&hypersecu=1';
url += '&google=1';
url += '&microsoft=1';
url += '&mds=1';
url += '&requireResidentKey=0';
url += '&type_usb=1';
url += '&type_nfc=1';
url += '&type_ble=1';
url += '&type_int=1';
url += '&type_hybrid=1';
url += '&fmt_android-key=1';
url += '&fmt_android-safetynet=1';
url += '&fmt_apple=1';
url += '&fmt_fido-u2f=1';
url += '&fmt_none=0' ;
url += '&fmt_packed=1';
url += '&fmt_tpm=1';
url += '&userVerification=discouraged';
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
* https://www.chartjs.org
* (c) 2023 chartjs-adapter-luxon Contributors
* Released under the MIT license
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("chart.js"),require("luxon")):"function"==typeof define&&define.amd?define(["chart.js","luxon"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Chart,e.luxon)}(this,(function(e,t){"use strict";const n={datetime:t.DateTime.DATETIME_MED_WITH_SECONDS,millisecond:"h:mm:ss.SSS a",second:t.DateTime.TIME_WITH_SECONDS,minute:t.DateTime.TIME_SIMPLE,hour:{hour:"numeric"},day:{day:"numeric",month:"short"},week:"DD",month:{month:"short",year:"numeric"},quarter:"'Q'q - yyyy",year:{year:"numeric"}};e._adapters._date.override({_id:"luxon",_create:function(e){return t.DateTime.fromMillis(e,this.options)},init(e){this.options.locale||(this.options.locale=e.locale)},formats:function(){return n},parse:function(e,n){const i=this.options,r=typeof e;return null===e||"undefined"===r?null:("number"===r?e=this._create(e):"string"===r?e="string"==typeof n?t.DateTime.fromFormat(e,n,i):t.DateTime.fromISO(e,i):e instanceof Date?e=t.DateTime.fromJSDate(e,i):"object"!==r||e instanceof t.DateTime||(e=t.DateTime.fromObject(e,i)),e.isValid?e.valueOf():null)},format:function(e,t){const n=this._create(e);return"string"==typeof t?n.toFormat(t):n.toLocaleString(t)},add:function(e,t,n){const i={};return i[n]=t,this._create(e).plus(i).valueOf()},diff:function(e,t,n){return this._create(e).diff(this._create(t)).as(n).valueOf()},startOf:function(e,t,n){if("isoWeek"===t){n=Math.trunc(Math.min(Math.max(0,n),6));const t=this._create(e);return t.minus({days:(t.weekday-n+7)%7}).startOf("day").valueOf()}return t?this._create(e).startOf(t).valueOf():e},endOf:function(e,t){return this._create(e).endOf(t).valueOf()}})}));
/*!
* chartjs-adapter-luxon v1.3.1
* https://www.chartjs.org
* (c) 2023 chartjs-adapter-luxon Contributors
* Released under the MIT license
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("chart.js"),require("luxon")):"function"==typeof define&&define.amd?define(["chart.js","luxon"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Chart,e.luxon)}(this,(function(e,t){"use strict";const n={datetime:t.DateTime.DATETIME_MED_WITH_SECONDS,millisecond:"h:mm:ss.SSS a",second:t.DateTime.TIME_WITH_SECONDS,minute:t.DateTime.TIME_SIMPLE,hour:{hour:"numeric"},day:{day:"numeric",month:"short"},week:"DD",month:{month:"short",year:"numeric"},quarter:"'Q'q - yyyy",year:{year:"numeric"}};e._adapters._date.override({_id:"luxon",_create:function(e){return t.DateTime.fromMillis(e,this.options)},init(e){this.options.locale||(this.options.locale=e.locale)},formats:function(){return n},parse:function(e,n){const i=this.options,r=typeof e;return null===e||"undefined"===r?null:("number"===r?e=this._create(e):"string"===r?e="string"==typeof n?t.DateTime.fromFormat(e,n,i):t.DateTime.fromISO(e,i):e instanceof Date?e=t.DateTime.fromJSDate(e,i):"object"!==r||e instanceof t.DateTime||(e=t.DateTime.fromObject(e,i)),e.isValid?e.valueOf():null)},format:function(e,t){const n=this._create(e);return"string"==typeof t?n.toFormat(t):n.toLocaleString(t)},add:function(e,t,n){const i={};return i[n]=t,this._create(e).plus(i).valueOf()},diff:function(e,t,n){return this._create(e).diff(this._create(t)).as(n).valueOf()},startOf:function(e,t,n){if("isoWeek"===t){n=Math.trunc(Math.min(Math.max(0,n),6));const t=this._create(e);return t.minus({days:(t.weekday-n+7)%7}).startOf("day").valueOf()}return t?this._create(e).startOf(t).valueOf():e},endOf:function(e,t){return this._create(e).endOf(t).valueOf()}})}));

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()});

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,22 +1,22 @@
MIT License
Copyright © 2022 Lukas Buchs
Copyright © 2018 Thomas Bleeker (CBOR & ByteBuffer part)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
SOFTWARE.
MIT License
Copyright © 2022 Lukas Buchs
Copyright © 2018 Thomas Bleeker (CBOR & ByteBuffer part)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
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)
[![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)
# WebAuthn
*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.
## Manual
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
* android-key &#x2705;
* android-safetynet &#x2705;
* apple &#x2705;
* fido-u2f &#x2705;
* none &#x2705;
* packed &#x2705;
* tpm &#x2705;
> [!NOTE]
> This library supports authenticators which are signed with a X.509 certificate or which are self attested. ECDAA is not supported.
## Workflow
JAVASCRIPT | SERVER
------------------------------------------------------------
REGISTRATION
window.fetch -----------------> getCreateArgs
|
navigator.credentials.create <-------------'
|
'-------------------------> processCreate
|
alert ok or fail <----------------'
------------------------------------------------------------
VALIDATION
window.fetch ------------------> getGetArgs
|
navigator.credentials.get <----------------'
|
'-------------------------> processGet
|
alert ok or fail <----------------'
## Attestation
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.
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
are signed with their own root certificate, enabling them to validate that an authenticator is affiliated with
their organization.
### no attestation
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.
> [!TIP]
> this is propably what you want to use if you want secure login for a public website.
### indirect attestation
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).
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.
> [!TIP]
> hybrid soultion, clients may be discouraged by browser warnings but then you know what device they're using (statistics rulez!)
### 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.
this library sets attestation to direct, if you select multiple formats and provide root ca's.
> [!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.
## 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,
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.
>[!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.
### 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.
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.
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).
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.
### How can I use it with this library?
#### on registration
When calling `WebAuthn\WebAuthn->getCreateArgs`, set `$requireResidentKey` to true,
to notify the authenticator that he should save the registration in its memory.
#### 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).
Set the type of authenticator to `hybrid` (Passkey scanned via QR Code) and `internal` (Passkey stored on the device itself).
#### 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.
### 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+
* Android 9+
* Microsoft Windows 11 23H2+
## 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)
* 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
## Infos about WebAuthn
* [Wikipedia](https://en.wikipedia.org/wiki/WebAuthn)
* [W3C](https://www.w3.org/TR/webauthn/)
* [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API)
* [dev.yubico](https://developers.yubico.com/FIDO2/)
* [FIDO Alliance](https://fidoalliance.org)
* [passkeys](https://passkeys.dev/)
## FIDO2 Hardware
* [Yubico](https://www.yubico.com)
* [Solo](https://solokeys.com) Open Source!
* [Nitrokey](https://www.nitrokey.com/)
* [Feitan](https://fido.ftsafe.com/)
* [TrustKey](https://www.trustkeysolutions.com)
* [Google Titan](https://cloud.google.com/titan-security-key)
* [Egis](https://www.egistec.com/u2f-solution/)
* [OneSpan](https://www.vasco.com/products/two-factor-authenticators/hardware/one-button/digipass-secureclick.html)
* [Hypersecu](https://hypersecu.com/tmp/products/hyperfido)
* [Kensington VeriMark™](https://www.kensington.com/)
* [Token2](https://www.token2.com/shop/category/fido2-keys)
[![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)
[![Last Commit](https://img.shields.io/github/last-commit/lbuchs/WebAuthn.svg)](https://github.com/lbuchs/WebAuthn/commits/master)
# WebAuthn
*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.
## Manual
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
* android-key &#x2705;
* android-safetynet &#x2705;
* apple &#x2705;
* fido-u2f &#x2705;
* none &#x2705;
* packed &#x2705;
* tpm &#x2705;
> [!NOTE]
> This library supports authenticators which are signed with a X.509 certificate or which are self attested. ECDAA is not supported.
## Workflow
JAVASCRIPT | SERVER
------------------------------------------------------------
REGISTRATION
window.fetch -----------------> getCreateArgs
|
navigator.credentials.create <-------------'
|
'-------------------------> processCreate
|
alert ok or fail <----------------'
------------------------------------------------------------
VALIDATION
window.fetch ------------------> getGetArgs
|
navigator.credentials.get <----------------'
|
'-------------------------> processGet
|
alert ok or fail <----------------'
## Attestation
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.
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
are signed with their own root certificate, enabling them to validate that an authenticator is affiliated with
their organization.
### no attestation
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.
> [!TIP]
> this is propably what you want to use if you want secure login for a public website.
### indirect attestation
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).
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.
> [!TIP]
> hybrid soultion, clients may be discouraged by browser warnings but then you know what device they're using (statistics rulez!)
### 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.
this library sets attestation to direct, if you select multiple formats and provide root ca's.
> [!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.
## 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,
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.
>[!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.
### 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.
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.
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).
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.
### How can I use it with this library?
#### on registration
When calling `WebAuthn\WebAuthn->getCreateArgs`, set `$requireResidentKey` to true,
to notify the authenticator that he should save the registration in its memory.
#### 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).
Set the type of authenticator to `hybrid` (Passkey scanned via QR Code) and `internal` (Passkey stored on the device itself).
#### 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.
### 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+
* Android 9+
* Microsoft Windows 11 23H2+
## 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)
* 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
## Infos about WebAuthn
* [Wikipedia](https://en.wikipedia.org/wiki/WebAuthn)
* [W3C](https://www.w3.org/TR/webauthn/)
* [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API)
* [dev.yubico](https://developers.yubico.com/FIDO2/)
* [FIDO Alliance](https://fidoalliance.org)
* [passkeys](https://passkeys.dev/)
## FIDO2 Hardware
* [Yubico](https://www.yubico.com)
* [Solo](https://solokeys.com) Open Source!
* [Nitrokey](https://www.nitrokey.com/)
* [Feitan](https://fido.ftsafe.com/)
* [TrustKey](https://www.trustkeysolutions.com)
* [Google Titan](https://cloud.google.com/titan-security-key)
* [Egis](https://www.egistec.com/u2f-solution/)
* [OneSpan](https://www.vasco.com/products/two-factor-authenticators/hardware/one-button/digipass-secureclick.html)
* [Hypersecu](https://hypersecu.com/tmp/products/hyperfido)
* [Kensington VeriMark™](https://www.kensington.com/)
* [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:
Data:
Version: 3 (0x2)
Serial Number:
68:1d:01:6c:7a:3c:e3:02:25:a5:01:94:28:47:57:71
Signature Algorithm: ecdsa-with-SHA384
Issuer:
stateOrProvinceName = California
organizationName = Apple Inc.
commonName = Apple WebAuthn Root CA
Validity
Not Before: Mar 18 18:21:32 2020 GMT
Not After : Mar 15 00:00:00 2045 GMT
Subject:
stateOrProvinceName = California
organizationName = Apple Inc.
commonName = Apple WebAuthn Root CA
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
ASN1 OID: secp384r1
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
26:D7:64:D9:C5:78:C2:5A:67:D1:A7:DE:6B:12:D0:1B:63:F1:C6:D7
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
-----BEGIN CERTIFICATE-----
MIICEjCCAZmgAwIBAgIQaB0BbHo84wIlpQGUKEdXcTAKBggqhkjOPQQDAzBLMR8w
HQYDVQQDDBZBcHBsZSBXZWJBdXRobiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ
bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIwMDMxODE4MjEzMloXDTQ1MDMx
NTAwMDAwMFowSzEfMB0GA1UEAwwWQXBwbGUgV2ViQXV0aG4gUm9vdCBDQTETMBEG
A1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTB2MBAGByqGSM49
AgEGBSuBBAAiA2IABCJCQ2pTVhzjl4Wo6IhHtMSAzO2cv+H9DQKev3//fG59G11k
xu9eI0/7o6V5uShBpe1u6l6mS19S1FEh6yGljnZAJ+2GNP1mi/YK2kSXIuTHjxA/
pcoRf7XkOtO4o1qlcaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJtdk
2cV4wlpn0afeaxLQG2PxxtcwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA
MGQCMFrZ+9DsJ1PW9hfNdBywZDsWDbWFp28it1d/5w2RPkRX3Bbn/UbDTNLx7Jr3
jAGGiQIwHFj+dJZYUJR786osByBelJYsVZd2GbHQu209b5RCmGQ21gpSAk9QZW4B
1bWeT0vT
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
68:1d:01:6c:7a:3c:e3:02:25:a5:01:94:28:47:57:71
Signature Algorithm: ecdsa-with-SHA384
Issuer:
stateOrProvinceName = California
organizationName = Apple Inc.
commonName = Apple WebAuthn Root CA
Validity
Not Before: Mar 18 18:21:32 2020 GMT
Not After : Mar 15 00:00:00 2045 GMT
Subject:
stateOrProvinceName = California
organizationName = Apple Inc.
commonName = Apple WebAuthn Root CA
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
ASN1 OID: secp384r1
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
26:D7:64:D9:C5:78:C2:5A:67:D1:A7:DE:6B:12:D0:1B:63:F1:C6:D7
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
-----BEGIN CERTIFICATE-----
MIICEjCCAZmgAwIBAgIQaB0BbHo84wIlpQGUKEdXcTAKBggqhkjOPQQDAzBLMR8w
HQYDVQQDDBZBcHBsZSBXZWJBdXRobiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ
bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIwMDMxODE4MjEzMloXDTQ1MDMx
NTAwMDAwMFowSzEfMB0GA1UEAwwWQXBwbGUgV2ViQXV0aG4gUm9vdCBDQTETMBEG
A1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTB2MBAGByqGSM49
AgEGBSuBBAAiA2IABCJCQ2pTVhzjl4Wo6IhHtMSAzO2cv+H9DQKev3//fG59G11k
xu9eI0/7o6V5uShBpe1u6l6mS19S1FEh6yGljnZAJ+2GNP1mi/YK2kSXIuTHjxA/
pcoRf7XkOtO4o1qlcaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJtdk
2cV4wlpn0afeaxLQG2PxxtcwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA
MGQCMFrZ+9DsJ1PW9hfNdBywZDsWDbWFp28it1d/5w2RPkRX3Bbn/UbDTNLx7Jr3
jAGGiQIwHFj+dJZYUJR786osByBelJYsVZd2GbHQu209b5RCmGQ21gpSAk9QZW4B
1bWeT0vT
-----END CERTIFICATE-----

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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