Initial commit
49
.gitignore
vendored
Normal file
@ -0,0 +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
|
||||||
245
README.md
@ -1,245 +0,0 @@
|
|||||||
# Normalisierte Datenbankstruktur für Somfy Tahoma
|
|
||||||
|
|
||||||
## Übersicht
|
|
||||||
|
|
||||||
Die Datenbank wurde von einer denormalisierten Struktur (mit JSON in `parameters`)
|
|
||||||
in eine vollständig normalisierte relationale Struktur überführt.
|
|
||||||
|
|
||||||
## Datenbankschema
|
|
||||||
|
|
||||||
### Haupttabellen
|
|
||||||
|
|
||||||
#### `actors`
|
|
||||||
Speichert alle Aktoren (Geräte mit Steuerungsfunktion)
|
|
||||||
|
|
||||||
| Spalte | Typ | Beschreibung |
|
|
||||||
|--------|-----|--------------|
|
|
||||||
| id | INT (PK, AUTO_INCREMENT) | Eindeutige ID |
|
|
||||||
| type | VARCHAR(50) | Gerätetyp (z.B. RollerShutter) |
|
|
||||||
| name | VARCHAR(70) | Name des Geräts |
|
|
||||||
| parameters | TEXT (nullable) | Optionale Meta-Informationen |
|
|
||||||
| url | VARCHAR(100) UNIQUE | Tahoma Device URL |
|
|
||||||
|
|
||||||
#### `sensors`
|
|
||||||
Speichert alle Sensoren (Geräte die Werte melden)
|
|
||||||
|
|
||||||
| Spalte | Typ | Beschreibung |
|
|
||||||
|--------|-----|--------------|
|
|
||||||
| id | INT (PK, AUTO_INCREMENT) | Eindeutige ID |
|
|
||||||
| type | VARCHAR(50) | Sensortyp (z.B. TemperatureSensor) |
|
|
||||||
| name | VARCHAR(70) | Name des Sensors |
|
|
||||||
| parameters | TEXT (nullable) | Optionale Meta-Informationen |
|
|
||||||
| url | VARCHAR(100) UNIQUE | Tahoma Device URL |
|
|
||||||
|
|
||||||
### Aktor-Detailtabellen
|
|
||||||
|
|
||||||
#### `actor_commands`
|
|
||||||
Speichert alle verfügbaren Commands für jeden Aktor
|
|
||||||
|
|
||||||
| Spalte | Typ | Beschreibung |
|
|
||||||
|--------|-----|--------------|
|
|
||||||
| id | INT (PK, AUTO_INCREMENT) | Eindeutige ID |
|
|
||||||
| actor_id | INT (FK → actors.id) | Referenz zum Aktor |
|
|
||||||
| command_name | VARCHAR(100) | Name des Commands (z.B. setPosition, open) |
|
|
||||||
|
|
||||||
**Beispieldaten:**
|
|
||||||
```
|
|
||||||
actor_id | command_name
|
|
||||||
---------|-------------
|
|
||||||
1 | open
|
|
||||||
1 | close
|
|
||||||
1 | setPosition
|
|
||||||
2 | on
|
|
||||||
2 | off
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `command_parameters`
|
|
||||||
Speichert die Parameter für jeden Command
|
|
||||||
|
|
||||||
| Spalte | Typ | Beschreibung |
|
|
||||||
|--------|-----|--------------|
|
|
||||||
| id | INT (PK, AUTO_INCREMENT) | Eindeutige ID |
|
|
||||||
| command_id | INT (FK → actor_commands.id) | Referenz zum Command |
|
|
||||||
| parameter_name | VARCHAR(100) | Name des Parameters (z.B. position) |
|
|
||||||
| parameter_type | VARCHAR(50) | Datentyp (z.B. integer, string) |
|
|
||||||
| min_value | DECIMAL(10,2) | Minimaler Wert (nullable) |
|
|
||||||
| max_value | DECIMAL(10,2) | Maximaler Wert (nullable) |
|
|
||||||
| possible_values | TEXT | JSON Array mit möglichen Werten (nullable) |
|
|
||||||
|
|
||||||
**Beispieldaten:**
|
|
||||||
```
|
|
||||||
command_id | parameter_name | parameter_type | min_value | max_value
|
|
||||||
-----------|----------------|----------------|-----------|----------
|
|
||||||
3 | position | integer | 0 | 100
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `actor_states`
|
|
||||||
Speichert die aktuellen States von Aktoren
|
|
||||||
|
|
||||||
| Spalte | Typ | Beschreibung |
|
|
||||||
|--------|-----|--------------|
|
|
||||||
| id | INT (PK, AUTO_INCREMENT) | Eindeutige ID |
|
|
||||||
| actor_id | INT (FK → actors.id) | Referenz zum Aktor |
|
|
||||||
| state_name | VARCHAR(100) | Name des State (z.B. core:ClosureState) |
|
|
||||||
| state_type | INT | State-Typ Code aus Tahoma API |
|
|
||||||
| current_value | VARCHAR(255) | Aktueller Wert |
|
|
||||||
| unit | VARCHAR(20) | Einheit (nullable) |
|
|
||||||
| last_updated | TIMESTAMP | Zeitpunkt der letzten Aktualisierung |
|
|
||||||
|
|
||||||
### Sensor-Detailtabellen
|
|
||||||
|
|
||||||
#### `sensor_states`
|
|
||||||
Speichert alle verfügbaren States für jeden Sensor
|
|
||||||
|
|
||||||
| Spalte | Typ | Beschreibung |
|
|
||||||
|--------|-----|--------------|
|
|
||||||
| id | INT (PK, AUTO_INCREMENT) | Eindeutige ID |
|
|
||||||
| sensor_id | INT (FK → sensors.id) | Referenz zum Sensor |
|
|
||||||
| state_name | VARCHAR(100) | Name des State (z.B. core:TemperatureState) |
|
|
||||||
| state_type | INT | State-Typ Code aus Tahoma API |
|
|
||||||
| current_value | VARCHAR(255) | Aktueller Wert |
|
|
||||||
| unit | VARCHAR(20) | Einheit (z.B. °C, %) (nullable) |
|
|
||||||
| last_updated | TIMESTAMP | Zeitpunkt der letzten Aktualisierung |
|
|
||||||
|
|
||||||
**Beispieldaten:**
|
|
||||||
```
|
|
||||||
sensor_id | state_name | state_type | current_value | unit
|
|
||||||
----------|-------------------------|------------|---------------|------
|
|
||||||
1 | core:TemperatureState | 1 | 21.5 | °C
|
|
||||||
2 | core:LuminanceState | 1 | 350 | lux
|
|
||||||
```
|
|
||||||
|
|
||||||
## Beziehungen (Foreign Keys)
|
|
||||||
|
|
||||||
```
|
|
||||||
actors (1) ──< (N) actor_commands
|
|
||||||
└──< (N) command_parameters
|
|
||||||
|
|
||||||
actors (1) ──< (N) actor_states
|
|
||||||
|
|
||||||
sensors (1) ──< (N) sensor_states
|
|
||||||
```
|
|
||||||
|
|
||||||
Alle Foreign Keys mit `ON DELETE CASCADE` → Wenn ein Aktor/Sensor gelöscht wird,
|
|
||||||
werden automatisch alle zugehörigen Commands, Parameter und States gelöscht.
|
|
||||||
|
|
||||||
## Hilfreiche Views
|
|
||||||
|
|
||||||
### `view_actors_with_commands`
|
|
||||||
Zeigt alle Aktoren mit ihren Commands und Parametern in einer flachen Ansicht
|
|
||||||
|
|
||||||
```sql
|
|
||||||
SELECT * FROM view_actors_with_commands WHERE actor_name = 'Wohnzimmer Rollo';
|
|
||||||
```
|
|
||||||
|
|
||||||
### `view_sensors_with_states`
|
|
||||||
Zeigt alle Sensoren mit ihren aktuellen States
|
|
||||||
|
|
||||||
```sql
|
|
||||||
SELECT * FROM view_sensors_with_states WHERE sensor_type = 'TemperatureSensor';
|
|
||||||
```
|
|
||||||
|
|
||||||
### `view_all_devices`
|
|
||||||
Zeigt eine Übersicht aller Geräte (Aktoren und Sensoren)
|
|
||||||
|
|
||||||
```sql
|
|
||||||
SELECT * FROM view_all_devices ORDER BY name;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Beispiel-Queries
|
|
||||||
|
|
||||||
### Alle Commands eines bestimmten Aktors anzeigen
|
|
||||||
```sql
|
|
||||||
SELECT
|
|
||||||
a.name as aktor_name,
|
|
||||||
ac.command_name,
|
|
||||||
cp.parameter_name,
|
|
||||||
cp.min_value,
|
|
||||||
cp.max_value
|
|
||||||
FROM actors a
|
|
||||||
JOIN actor_commands ac ON a.id = ac.actor_id
|
|
||||||
LEFT JOIN command_parameters cp ON ac.id = cp.command_id
|
|
||||||
WHERE a.name = 'Wohnzimmer Rollo';
|
|
||||||
```
|
|
||||||
|
|
||||||
### Alle Temperatursensoren mit aktuellem Wert
|
|
||||||
```sql
|
|
||||||
SELECT
|
|
||||||
s.name as sensor_name,
|
|
||||||
ss.current_value as temperatur,
|
|
||||||
ss.unit,
|
|
||||||
ss.last_updated
|
|
||||||
FROM sensors s
|
|
||||||
JOIN sensor_states ss ON s.id = ss.sensor_id
|
|
||||||
WHERE s.type = 'TemperatureSensor'
|
|
||||||
AND ss.state_name LIKE '%Temperature%';
|
|
||||||
```
|
|
||||||
|
|
||||||
### Alle Aktoren eines bestimmten Typs
|
|
||||||
```sql
|
|
||||||
SELECT
|
|
||||||
name,
|
|
||||||
type,
|
|
||||||
COUNT(DISTINCT ac.id) as anzahl_commands
|
|
||||||
FROM actors a
|
|
||||||
LEFT JOIN actor_commands ac ON a.id = ac.actor_id
|
|
||||||
WHERE a.type = 'RollerShutter'
|
|
||||||
GROUP BY a.id, a.name, a.type;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Commands ohne Parameter finden
|
|
||||||
```sql
|
|
||||||
SELECT
|
|
||||||
a.name as aktor,
|
|
||||||
ac.command_name
|
|
||||||
FROM actors a
|
|
||||||
JOIN actor_commands ac ON a.id = ac.actor_id
|
|
||||||
LEFT JOIN command_parameters cp ON ac.id = cp.command_id
|
|
||||||
WHERE cp.id IS NULL;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Vorteile der normalisierten Struktur
|
|
||||||
|
|
||||||
1. **Keine Datenduplizierung**: Jeder Command und Parameter wird nur einmal gespeichert
|
|
||||||
2. **Einfache Queries**: SQL-Joins statt JSON-Parsing
|
|
||||||
3. **Flexible Erweiterung**: Neue Spalten können einfach hinzugefügt werden
|
|
||||||
4. **Referentielle Integrität**: Foreign Keys garantieren Konsistenz
|
|
||||||
5. **Performance**: Indizes auf relevanten Spalten für schnelle Suchen
|
|
||||||
6. **Typsicherheit**: Min/Max als DECIMAL statt String
|
|
||||||
|
|
||||||
## Migration von alter zu neuer Struktur
|
|
||||||
|
|
||||||
Falls Sie bereits Daten in der alten Struktur haben:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
-- Backup erstellen
|
|
||||||
CREATE TABLE actors_old AS SELECT * FROM actors;
|
|
||||||
CREATE TABLE sensors_old AS SELECT * FROM sensors;
|
|
||||||
|
|
||||||
-- Alte Tabellen löschen
|
|
||||||
DROP TABLE actors;
|
|
||||||
DROP TABLE sensors;
|
|
||||||
|
|
||||||
-- Neue Struktur erstellen (database_schema.sql ausführen)
|
|
||||||
SOURCE database_schema.sql;
|
|
||||||
|
|
||||||
-- Python-Script ausführen um Daten neu zu importieren
|
|
||||||
```
|
|
||||||
|
|
||||||
## Wartung
|
|
||||||
|
|
||||||
### Regelmäßige Aktualisierung der States
|
|
||||||
Das Script kann regelmäßig ausgeführt werden. Bei `CLEAR_TABLES = True` werden
|
|
||||||
alle Daten neu importiert. Bei `CLEAR_TABLES = False` können Updates implementiert werden.
|
|
||||||
|
|
||||||
### Veraltete Geräte entfernen
|
|
||||||
```sql
|
|
||||||
-- Geräte finden die nicht mehr in der Tahoma Box vorhanden sind
|
|
||||||
-- (nach erneutem Import)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Index-Optimierung prüfen
|
|
||||||
```sql
|
|
||||||
SHOW INDEX FROM actors;
|
|
||||||
SHOW INDEX FROM actor_commands;
|
|
||||||
```
|
|
||||||
16
addUser.php
Normal file
@ -0,0 +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;
|
||||||
|
}
|
||||||
|
?>
|
||||||
264
ajax/AutoAction.php
Normal file
@ -0,0 +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('+','-','=','<','>','!='))) {
|
||||||
|
$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> 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">></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> 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> 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">></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;
|
||||||
|
}
|
||||||
12
ajax/actorDetails.php
Normal file
@ -0,0 +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];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
||||||
141
ajax/carEG.php
Normal file
@ -0,0 +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;
|
||||||
|
}
|
||||||
148
ajax/carOG.php
Normal file
@ -0,0 +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 . "&=" . $_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 . "&=" . $_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 . "&=" . $_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;
|
||||||
|
}
|
||||||
11
ajax/fillActorDD.php
Normal file
@ -0,0 +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>";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
11
ajax/fillSensorDD.php
Normal file
@ -0,0 +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>";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
162
ajax/getConsData.php
Normal file
@ -0,0 +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]}]}';
|
||||||
|
?>
|
||||||
98
ajax/getConsData_decade.php
Normal file
@ -0,0 +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]}]}';
|
||||||
98
ajax/getConsData_month.php
Normal file
@ -0,0 +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]}]}';
|
||||||
98
ajax/getConsData_year.php
Normal file
@ -0,0 +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]}]}';
|
||||||
175
ajax/getForecastData.php
Normal file
@ -0,0 +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]}]}';
|
||||||
105
ajax/getHeaterData.php
Normal file
@ -0,0 +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]}]}';
|
||||||
165
ajax/getProdData.php
Normal file
@ -0,0 +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]}]}';
|
||||||
|
?>
|
||||||
98
ajax/getProdData_decade.php
Normal file
@ -0,0 +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]}]}';
|
||||||
98
ajax/getProdData_month.php
Normal file
@ -0,0 +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]}]}';
|
||||||
98
ajax/getProdData_year.php
Normal file
@ -0,0 +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]}]}';
|
||||||
155
ajax/getStats.php
Normal file
@ -0,0 +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]}]}';
|
||||||
65
ajax/getSunrise.php
Normal file
@ -0,0 +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]}]}';
|
||||||
65
ajax/getWaterData.php
Normal file
@ -0,0 +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]}]}';
|
||||||
73
ajax/heater.php
Normal file
@ -0,0 +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;
|
||||||
|
}
|
||||||
671
ajax/phpMQTT.php
Normal file
@ -0,0 +1,671 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bluerhinos;
|
||||||
|
|
||||||
|
/*
|
||||||
|
phpMQTT
|
||||||
|
A simple php class to connect/publish/subscribe to an MQTT broker
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Licence
|
||||||
|
|
||||||
|
Copyright (c) 2010 Blue Rhinos Consulting | Andrew Milsted
|
||||||
|
andrew@bluerhinos.co.uk | http://www.bluerhinos.co.uk
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* phpMQTT */
|
||||||
|
|
||||||
|
class phpMQTT
|
||||||
|
{
|
||||||
|
protected $socket; /* holds the socket */
|
||||||
|
protected $msgid = 1; /* counter for message id */
|
||||||
|
public $keepalive = 10; /* default keepalive timmer */
|
||||||
|
public $timesinceping; /* host unix time, used to detect disconects */
|
||||||
|
public $topics = []; /* used to store currently subscribed topics */
|
||||||
|
public $debug = false; /* should output debug messages */
|
||||||
|
public $address; /* broker address */
|
||||||
|
public $port; /* broker port */
|
||||||
|
public $clientid; /* client id sent to brocker */
|
||||||
|
public $will; /* stores the will of the client */
|
||||||
|
protected $username; /* stores username */
|
||||||
|
protected $password; /* stores password */
|
||||||
|
|
||||||
|
public $cafile;
|
||||||
|
protected static $known_commands = [
|
||||||
|
1 => 'CONNECT',
|
||||||
|
2 => 'CONNACK',
|
||||||
|
3 => 'PUBLISH',
|
||||||
|
4 => 'PUBACK',
|
||||||
|
5 => 'PUBREC',
|
||||||
|
6 => 'PUBREL',
|
||||||
|
7 => 'PUBCOMP',
|
||||||
|
8 => 'SUBSCRIBE',
|
||||||
|
9 => 'SUBACK',
|
||||||
|
10 => 'UNSUBSCRIBE',
|
||||||
|
11 => 'UNSUBACK',
|
||||||
|
12 => 'PINGREQ',
|
||||||
|
13 => 'PINGRESP',
|
||||||
|
14 => 'DISCONNECT'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* phpMQTT constructor.
|
||||||
|
*
|
||||||
|
* @param $address
|
||||||
|
* @param $port
|
||||||
|
* @param $clientid
|
||||||
|
* @param null $cafile
|
||||||
|
*/
|
||||||
|
public function __construct($address, $port, $clientid, $cafile = null)
|
||||||
|
{
|
||||||
|
$this->broker($address, $port, $clientid, $cafile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the broker details
|
||||||
|
*
|
||||||
|
* @param $address
|
||||||
|
* @param $port
|
||||||
|
* @param $clientid
|
||||||
|
* @param null $cafile
|
||||||
|
*/
|
||||||
|
public function broker($address, $port, $clientid, $cafile = null): void
|
||||||
|
{
|
||||||
|
$this->address = $address;
|
||||||
|
$this->port = $port;
|
||||||
|
$this->clientid = $clientid;
|
||||||
|
$this->cafile = $cafile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will try and connect, if fails it will sleep 10s and try again, this will enable the script to recover from a network outage
|
||||||
|
*
|
||||||
|
* @param bool $clean - should the client send a clean session flag
|
||||||
|
* @param null $will
|
||||||
|
* @param null $username
|
||||||
|
* @param null $password
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function connect_auto($clean = true, $will = null, $username = null, $password = null): bool
|
||||||
|
{
|
||||||
|
while ($this->connect($clean, $will, $username, $password) === false) {
|
||||||
|
sleep(10);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $clean - should the client send a clean session flag
|
||||||
|
* @param null $will
|
||||||
|
* @param null $username
|
||||||
|
* @param null $password
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function connect($clean = true, $will = null, $username = null, $password = null): bool
|
||||||
|
{
|
||||||
|
if ($will) {
|
||||||
|
$this->will = $will;
|
||||||
|
}
|
||||||
|
if ($username) {
|
||||||
|
$this->username = $username;
|
||||||
|
}
|
||||||
|
if ($password) {
|
||||||
|
$this->password = $password;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->cafile) {
|
||||||
|
$socketContext = stream_context_create(
|
||||||
|
[
|
||||||
|
'ssl' => [
|
||||||
|
'verify_peer_name' => true,
|
||||||
|
'cafile' => $this->cafile
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$this->socket = stream_socket_client('tls://' . $this->address . ':' . $this->port, $errno, $errstr, 60, STREAM_CLIENT_CONNECT, $socketContext);
|
||||||
|
} else {
|
||||||
|
$this->socket = stream_socket_client('tcp://' . $this->address . ':' . $this->port, $errno, $errstr, 60, STREAM_CLIENT_CONNECT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->socket) {
|
||||||
|
$this->_errorMessage("stream_socket_create() $errno, $errstr");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_set_timeout($this->socket, 5);
|
||||||
|
stream_set_blocking($this->socket, 0);
|
||||||
|
|
||||||
|
$i = 0;
|
||||||
|
$buffer = '';
|
||||||
|
|
||||||
|
$buffer .= chr(0x00);
|
||||||
|
$i++; // Length MSB
|
||||||
|
$buffer .= chr(0x04);
|
||||||
|
$i++; // Length LSB
|
||||||
|
$buffer .= chr(0x4d);
|
||||||
|
$i++; // M
|
||||||
|
$buffer .= chr(0x51);
|
||||||
|
$i++; // Q
|
||||||
|
$buffer .= chr(0x54);
|
||||||
|
$i++; // T
|
||||||
|
$buffer .= chr(0x54);
|
||||||
|
$i++; // T
|
||||||
|
$buffer .= chr(0x04);
|
||||||
|
$i++; // // Protocol Level
|
||||||
|
|
||||||
|
//No Will
|
||||||
|
$var = 0;
|
||||||
|
if ($clean) {
|
||||||
|
$var += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add will info to header
|
||||||
|
if ($this->will !== null) {
|
||||||
|
$var += 4; // Set will flag
|
||||||
|
$var += ($this->will['qos'] << 3); //Set will qos
|
||||||
|
if ($this->will['retain']) {
|
||||||
|
$var += 32;
|
||||||
|
} //Set will retain
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->username !== null) {
|
||||||
|
$var += 128;
|
||||||
|
} //Add username to header
|
||||||
|
if ($this->password !== null) {
|
||||||
|
$var += 64;
|
||||||
|
} //Add password to header
|
||||||
|
|
||||||
|
$buffer .= chr($var);
|
||||||
|
$i++;
|
||||||
|
|
||||||
|
//Keep alive
|
||||||
|
$buffer .= chr($this->keepalive >> 8);
|
||||||
|
$i++;
|
||||||
|
$buffer .= chr($this->keepalive & 0xff);
|
||||||
|
$i++;
|
||||||
|
|
||||||
|
$buffer .= $this->strwritestring($this->clientid, $i);
|
||||||
|
|
||||||
|
//Adding will to payload
|
||||||
|
if ($this->will !== null) {
|
||||||
|
$buffer .= $this->strwritestring($this->will['topic'], $i);
|
||||||
|
$buffer .= $this->strwritestring($this->will['content'], $i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->username !== null) {
|
||||||
|
$buffer .= $this->strwritestring($this->username, $i);
|
||||||
|
}
|
||||||
|
if ($this->password !== null) {
|
||||||
|
$buffer .= $this->strwritestring($this->password, $i);
|
||||||
|
}
|
||||||
|
|
||||||
|
$head = chr(0x10);
|
||||||
|
|
||||||
|
while ($i > 0) {
|
||||||
|
$encodedByte = $i % 128;
|
||||||
|
$i /= 128;
|
||||||
|
$i = (int)$i;
|
||||||
|
if ($i > 0) {
|
||||||
|
$encodedByte |= 128;
|
||||||
|
}
|
||||||
|
$head .= chr($encodedByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite($this->socket, $head, 2);
|
||||||
|
fwrite($this->socket, $buffer);
|
||||||
|
|
||||||
|
$string = $this->read(4);
|
||||||
|
|
||||||
|
if (ord($string[0]) >> 4 === 2 && $string[3] === chr(0)) {
|
||||||
|
$this->_debugMessage('Connected to Broker');
|
||||||
|
} else {
|
||||||
|
$this->_errorMessage(
|
||||||
|
sprintf(
|
||||||
|
"Connection failed! (Error: 0x%02x 0x%02x)\n",
|
||||||
|
ord($string[0]),
|
||||||
|
ord($string[3])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->timesinceping = time();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads in so many bytes
|
||||||
|
*
|
||||||
|
* @param int $int
|
||||||
|
* @param bool $nb
|
||||||
|
*
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
|
public function read($int = 8192, $nb = false)
|
||||||
|
{
|
||||||
|
$string = '';
|
||||||
|
$togo = $int;
|
||||||
|
|
||||||
|
if ($nb) {
|
||||||
|
return fread($this->socket, $togo);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!feof($this->socket) && $togo > 0) {
|
||||||
|
$fread = fread($this->socket, $togo);
|
||||||
|
$string .= $fread;
|
||||||
|
$togo = $int - strlen($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribes to a topic, wait for message and return it
|
||||||
|
*
|
||||||
|
* @param $topic
|
||||||
|
* @param $qos
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function subscribeAndWaitForMessage($topic, $qos): string
|
||||||
|
{
|
||||||
|
$this->subscribe(
|
||||||
|
[
|
||||||
|
$topic => [
|
||||||
|
'qos' => $qos,
|
||||||
|
'function' => '__direct_return_message__'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
do {
|
||||||
|
$return = $this->proc();
|
||||||
|
} while ($return === true);
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscribes to topics
|
||||||
|
*
|
||||||
|
* @param $topics
|
||||||
|
* @param int $qos
|
||||||
|
*/
|
||||||
|
public function subscribe($topics, $qos = 0): void
|
||||||
|
{
|
||||||
|
$i = 0;
|
||||||
|
$buffer = '';
|
||||||
|
$id = $this->msgid;
|
||||||
|
$buffer .= chr($id >> 8);
|
||||||
|
$i++;
|
||||||
|
$buffer .= chr($id % 256);
|
||||||
|
$i++;
|
||||||
|
|
||||||
|
foreach ($topics as $key => $topic) {
|
||||||
|
$buffer .= $this->strwritestring($key, $i);
|
||||||
|
$buffer .= chr($topic['qos']);
|
||||||
|
$i++;
|
||||||
|
$this->topics[$key] = $topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cmd = 0x82;
|
||||||
|
//$qos
|
||||||
|
$cmd += ($qos << 1);
|
||||||
|
|
||||||
|
$head = chr($cmd);
|
||||||
|
$head .= $this->setmsglength($i);
|
||||||
|
fwrite($this->socket, $head, strlen($head));
|
||||||
|
|
||||||
|
$this->_fwrite($buffer);
|
||||||
|
$string = $this->read(2);
|
||||||
|
|
||||||
|
$bytes = ord(substr($string, 1, 1));
|
||||||
|
$this->read($bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a keep alive ping
|
||||||
|
*/
|
||||||
|
public function ping(): void
|
||||||
|
{
|
||||||
|
$head = chr(0xc0);
|
||||||
|
$head .= chr(0x00);
|
||||||
|
fwrite($this->socket, $head, 2);
|
||||||
|
$this->timesinceping = time();
|
||||||
|
$this->_debugMessage('ping sent');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends a proper disconnect cmd
|
||||||
|
*/
|
||||||
|
public function disconnect(): void
|
||||||
|
{
|
||||||
|
$head = ' ';
|
||||||
|
$head[0] = chr(0xe0);
|
||||||
|
$head[1] = chr(0x00);
|
||||||
|
fwrite($this->socket, $head, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a proper disconnect, then closes the socket
|
||||||
|
*/
|
||||||
|
public function close(): void
|
||||||
|
{
|
||||||
|
$this->disconnect();
|
||||||
|
stream_socket_shutdown($this->socket, STREAM_SHUT_WR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publishes $content on a $topic
|
||||||
|
*
|
||||||
|
* @param $topic
|
||||||
|
* @param $content
|
||||||
|
* @param int $qos
|
||||||
|
* @param bool $retain
|
||||||
|
*/
|
||||||
|
public function publish($topic, $content, $qos = 0, $retain = false): void
|
||||||
|
{
|
||||||
|
$i = 0;
|
||||||
|
$buffer = '';
|
||||||
|
|
||||||
|
$buffer .= $this->strwritestring($topic, $i);
|
||||||
|
|
||||||
|
if ($qos) {
|
||||||
|
$id = $this->msgid++;
|
||||||
|
$buffer .= chr($id >> 8);
|
||||||
|
$i++;
|
||||||
|
$buffer .= chr($id % 256);
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$buffer .= $content;
|
||||||
|
$i += strlen($content);
|
||||||
|
|
||||||
|
$head = ' ';
|
||||||
|
$cmd = 0x30;
|
||||||
|
if ($qos) {
|
||||||
|
$cmd += $qos << 1;
|
||||||
|
}
|
||||||
|
if (empty($retain) === false) {
|
||||||
|
++$cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
$head[0] = chr($cmd);
|
||||||
|
$head .= $this->setmsglength($i);
|
||||||
|
|
||||||
|
fwrite($this->socket, $head, strlen($head));
|
||||||
|
$this->_fwrite($buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a string to the socket
|
||||||
|
*
|
||||||
|
* @param $buffer
|
||||||
|
*
|
||||||
|
* @return bool|int
|
||||||
|
*/
|
||||||
|
protected function _fwrite($buffer)
|
||||||
|
{
|
||||||
|
$buffer_length = strlen($buffer);
|
||||||
|
for ($written = 0; $written < $buffer_length; $written += $fwrite) {
|
||||||
|
$fwrite = fwrite($this->socket, substr($buffer, $written));
|
||||||
|
if ($fwrite === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $buffer_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a received topic
|
||||||
|
*
|
||||||
|
* @param $msg
|
||||||
|
*
|
||||||
|
* @retrun bool|string
|
||||||
|
*/
|
||||||
|
public function message($msg)
|
||||||
|
{
|
||||||
|
$tlen = (ord($msg[0]) << 8) + ord($msg[1]);
|
||||||
|
$topic = substr($msg, 2, $tlen);
|
||||||
|
$msg = substr($msg, ($tlen + 2));
|
||||||
|
$found = false;
|
||||||
|
foreach ($this->topics as $key => $top) {
|
||||||
|
if (preg_match(
|
||||||
|
'/^' . str_replace(
|
||||||
|
'#',
|
||||||
|
'.*',
|
||||||
|
str_replace(
|
||||||
|
'+',
|
||||||
|
"[^\/]*",
|
||||||
|
str_replace(
|
||||||
|
'/',
|
||||||
|
"\/",
|
||||||
|
str_replace(
|
||||||
|
'$',
|
||||||
|
'\$',
|
||||||
|
$key
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) . '$/',
|
||||||
|
$topic
|
||||||
|
)) {
|
||||||
|
$found = true;
|
||||||
|
|
||||||
|
if ($top['function'] === '__direct_return_message__') {
|
||||||
|
return $msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_callable($top['function'])) {
|
||||||
|
call_user_func($top['function'], $topic, $msg);
|
||||||
|
} else {
|
||||||
|
$this->_errorMessage('Message received on topic ' . $topic . ' but function is not callable.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($found === false) {
|
||||||
|
$this->_debugMessage('msg received but no match in subscriptions');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The processing loop for an "always on" client
|
||||||
|
* set true when you are doing other stuff in the loop good for
|
||||||
|
* watching something else at the same time
|
||||||
|
*
|
||||||
|
* @param bool $loop
|
||||||
|
*
|
||||||
|
* @return bool | string
|
||||||
|
*/
|
||||||
|
public function proc(bool $loop = true)
|
||||||
|
{
|
||||||
|
if (feof($this->socket)) {
|
||||||
|
$this->_debugMessage('eof receive going to reconnect for good measure');
|
||||||
|
fclose($this->socket);
|
||||||
|
$this->connect_auto(false);
|
||||||
|
if (count($this->topics)) {
|
||||||
|
$this->subscribe($this->topics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$byte = $this->read(1, true);
|
||||||
|
|
||||||
|
if ((string)$byte === '') {
|
||||||
|
if ($loop === true) {
|
||||||
|
usleep(100000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$cmd = (int)(ord($byte) / 16);
|
||||||
|
$this->_debugMessage(
|
||||||
|
sprintf(
|
||||||
|
'Received CMD: %d (%s)',
|
||||||
|
$cmd,
|
||||||
|
isset(static::$known_commands[$cmd]) === true ? static::$known_commands[$cmd] : 'Unknown'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$multiplier = 1;
|
||||||
|
$value = 0;
|
||||||
|
do {
|
||||||
|
$digit = ord($this->read(1));
|
||||||
|
$value += ($digit & 127) * $multiplier;
|
||||||
|
$multiplier *= 128;
|
||||||
|
} while (($digit & 128) !== 0);
|
||||||
|
|
||||||
|
$this->_debugMessage('Fetching: ' . $value . ' bytes');
|
||||||
|
|
||||||
|
$string = $value > 0 ? $this->read($value) : '';
|
||||||
|
|
||||||
|
if ($cmd) {
|
||||||
|
switch ($cmd) {
|
||||||
|
case 3: //Publish MSG
|
||||||
|
$return = $this->message($string);
|
||||||
|
if (is_bool($return) === false) {
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->timesinceping < (time() - $this->keepalive)) {
|
||||||
|
$this->_debugMessage('not had something in a while so ping');
|
||||||
|
$this->ping();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->timesinceping < (time() - ($this->keepalive * 2))) {
|
||||||
|
$this->_debugMessage('not seen a packet in a while, disconnecting/reconnecting');
|
||||||
|
fclose($this->socket);
|
||||||
|
$this->connect_auto(false);
|
||||||
|
if (count($this->topics)) {
|
||||||
|
$this->subscribe($this->topics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the length of a msg, (and increments $i)
|
||||||
|
*
|
||||||
|
* @param $msg
|
||||||
|
* @param $i
|
||||||
|
*
|
||||||
|
* @return float|int
|
||||||
|
*/
|
||||||
|
protected function getmsglength(&$msg, &$i)
|
||||||
|
{
|
||||||
|
$multiplier = 1;
|
||||||
|
$value = 0;
|
||||||
|
do {
|
||||||
|
$digit = ord($msg[$i]);
|
||||||
|
$value += ($digit & 127) * $multiplier;
|
||||||
|
$multiplier *= 128;
|
||||||
|
$i++;
|
||||||
|
} while (($digit & 128) !== 0);
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $len
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function setmsglength($len): string
|
||||||
|
{
|
||||||
|
$string = '';
|
||||||
|
do {
|
||||||
|
$digit = $len % 128;
|
||||||
|
$len >>= 7;
|
||||||
|
// if there are more digits to encode, set the top bit of this digit
|
||||||
|
if ($len > 0) {
|
||||||
|
$digit |= 0x80;
|
||||||
|
}
|
||||||
|
$string .= chr($digit);
|
||||||
|
} while ($len > 0);
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $str
|
||||||
|
* @param $i
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function strwritestring($str, &$i): string
|
||||||
|
{
|
||||||
|
$len = strlen($str);
|
||||||
|
$msb = $len >> 8;
|
||||||
|
$lsb = $len % 256;
|
||||||
|
$ret = chr($msb);
|
||||||
|
$ret .= chr($lsb);
|
||||||
|
$ret .= $str;
|
||||||
|
$i += ($len + 2);
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a sting out character by character
|
||||||
|
*
|
||||||
|
* @param $string
|
||||||
|
*/
|
||||||
|
public function printstr($string): void
|
||||||
|
{
|
||||||
|
$strlen = strlen($string);
|
||||||
|
for ($j = 0; $j < $strlen; $j++) {
|
||||||
|
$num = ord($string[$j]);
|
||||||
|
if ($num > 31) {
|
||||||
|
$chr = $string[$j];
|
||||||
|
} else {
|
||||||
|
$chr = ' ';
|
||||||
|
}
|
||||||
|
printf("%4d: %08b : 0x%02x : %s \n", $j, $num, $num, $chr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $message
|
||||||
|
*/
|
||||||
|
protected function _debugMessage(string $message): void
|
||||||
|
{
|
||||||
|
if ($this->debug === true) {
|
||||||
|
echo date('r: ') . $message . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $message
|
||||||
|
*/
|
||||||
|
protected function _errorMessage(string $message): void
|
||||||
|
{
|
||||||
|
error_log('Error:' . $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
55
ajax/roomtemp.php
Normal file
@ -0,0 +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;
|
||||||
|
}
|
||||||
12
ajax/sensorDetails.php
Normal file
@ -0,0 +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];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
||||||
241
ajax/tahoma.php
Normal file
@ -0,0 +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));
|
||||||
|
}
|
||||||
144
assets/fonts/font_poppins.css
Normal file
@ -0,0 +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;
|
||||||
|
}
|
||||||
BIN
assets/fonts/pxiByp8kv8JHgFVrLCz7Z11lFc-K.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLCz7Z1JlFc-K.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLDD4Z11lFc-K.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLDD4Z1JlFc-K.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLDD4Z1xlFQ.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLDz8Z11lFc-K.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLDz8Z1JlFc-K.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLDz8Z1xlFQ.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLEj6Z11lFc-K.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLEj6Z1JlFc-K.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLEj6Z1xlFQ.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLFj_Z11lFc-K.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLFj_Z1JlFc-K.woff2
Normal file
BIN
assets/fonts/pxiByp8kv8JHgFVrLFj_Z1xlFQ.woff2
Normal file
BIN
assets/fonts/pxiEyp8kv8JHgFVrJJbecmNE.woff2
Normal file
BIN
assets/fonts/pxiEyp8kv8JHgFVrJJfecg.woff2
Normal file
BIN
assets/fonts/pxiEyp8kv8JHgFVrJJnecmNE.woff2
Normal file
BIN
assets/img/1UG.png
Normal file
|
After Width: | Height: | Size: 304 KiB |
BIN
assets/img/2EG.png
Normal file
|
After Width: | Height: | Size: 347 KiB |
BIN
assets/img/3OG.png
Normal file
|
After Width: | Height: | Size: 415 KiB |
BIN
assets/img/AdminLTEFullLogo.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
assets/img/AdminLTELogo.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
assets/img/EG.png
Normal file
|
After Width: | Height: | Size: 337 KiB |
BIN
assets/img/OG.png
Normal file
|
After Width: | Height: | Size: 393 KiB |
BIN
assets/img/UG.png
Normal file
|
After Width: | Height: | Size: 320 KiB |
5
assets/img/arrow.svg
Normal file
@ -0,0 +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>
|
||||||
|
After Width: | Height: | Size: 491 B |
BIN
assets/img/boxed-bg.jpg
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
assets/img/boxed-bg.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
assets/img/credit/american-express.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/img/credit/cirrus.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/img/credit/mastercard.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/img/credit/paypal.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
assets/img/credit/paypal2.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/img/credit/visa.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/img/default-150x150.png
Normal file
|
After Width: | Height: | Size: 339 B |
BIN
assets/img/favicon.png
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
assets/img/favicon2.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
287
assets/img/heater.svg
Normal file
@ -0,0 +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>
|
||||||
|
After Width: | Height: | Size: 7.8 KiB |
BIN
assets/img/icons.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
475
assets/img/pvDetail.svg
Normal file
@ -0,0 +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>
|
||||||
|
After Width: | Height: | Size: 32 KiB |
864
assets/img/realtime.svg
Normal file
@ -0,0 +1,864 @@
|
|||||||
|
<style>
|
||||||
|
.stream{
|
||||||
|
animation: stream 2s steps(40) infinite;
|
||||||
|
}
|
||||||
|
@keyframes stream {
|
||||||
|
100%{
|
||||||
|
stroke-dashoffset: -110;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.stream-rev{
|
||||||
|
animation: stream-rev 2s steps(40) infinite;
|
||||||
|
}
|
||||||
|
@keyframes stream-rev {
|
||||||
|
100%{
|
||||||
|
stroke-dashoffset: 110;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.powerTextClass {
|
||||||
|
font-size: 27px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
text-anchor: middle;
|
||||||
|
fill: rgb(200, 210, 210);
|
||||||
|
letter-spacing: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoTextClass {
|
||||||
|
font-size: 18px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
text-anchor: middle;
|
||||||
|
fill: rgb(200, 210, 210);
|
||||||
|
}
|
||||||
|
.tooltipTextClass {
|
||||||
|
font-size: 18px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
text-anchor: left;
|
||||||
|
fill: rgb(200, 210, 210);
|
||||||
|
}
|
||||||
|
.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="-100 -100 1600 950" width="100%" height="100%" id="realtimeSvgAni">
|
||||||
|
<defs>
|
||||||
|
<filter
|
||||||
|
id="glow" filterUnits="userSpaceOnUse"
|
||||||
|
x="-20%" y="-20%" width="120%" height="120%">
|
||||||
|
<feGaussianBlur in="SourceGraphic" stdDeviation="7" result="blur5" />
|
||||||
|
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur10" />
|
||||||
|
<feGaussianBlur in="SourceGraphic" stdDeviation="14" result="blur20" />
|
||||||
|
<feGaussianBlur in="SourceGraphic" stdDeviation="17" result="blur30" />
|
||||||
|
<feGaussianBlur in="SourceGraphic" stdDeviation="20" result="blur50" />
|
||||||
|
<feMerge result="blur-merged">
|
||||||
|
<feMergeNode in="blur5" />
|
||||||
|
<feMergeNode in="blur10" />
|
||||||
|
<feMergeNode in="blur10" />
|
||||||
|
<feMergeNode in="blur20" />
|
||||||
|
</feMerge>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode in="blur-merged" />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<g opacity="0">
|
||||||
|
<animate begin="lastInitAni.end" attributetype="CSS" attributeName="opacity" from="0.0" to="1.0"
|
||||||
|
dur="0.5s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
|
||||||
|
fill="freeze" />
|
||||||
|
<animate begin="pvInfo.click" attributetype="CSS" attributeName="opacity" from="1.0" to="0.0"
|
||||||
|
dur="1s"
|
||||||
|
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
|
||||||
|
<animate begin="closeDetails.click" attributetype="CSS" attributeName="opacity" from="0.0"
|
||||||
|
to="1.0"
|
||||||
|
dur="1s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
|
||||||
|
fill="freeze" />
|
||||||
|
<!-- CONS pos: 330, 280
|
||||||
|
+340, 0 (center +100 in x und y)
|
||||||
|
Cons OG pos: 330,280
|
||||||
|
+500 -300 (center +90 in x und y)
|
||||||
|
-->
|
||||||
|
<line x1="770" y1="380" x2="920" y2="70" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
|
<line id="consOGani" class="stream" x1="770" y1="380" x2="920" y2="70" stroke-linecap="round"
|
||||||
|
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
||||||
|
|
||||||
|
<line x1="430" y1="380" x2="770" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
|
<line id="consAni" class="stream" x1="430" y1="380" x2="770" y2="380" stroke-linecap="round"
|
||||||
|
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
||||||
|
|
||||||
|
<line x1="770" y1="380" x2="920" y2="670" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
|
<line id="consEGani" class="stream" x1="770" y1="380" x2="920" y2="670" stroke-linecap="round"
|
||||||
|
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
||||||
|
|
||||||
|
<line x1="770" y1="380" x2="600" y2="670" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
|
<line id="consUGani" class="stream" x1="770" y1="380" x2="600" y2="670" stroke-linecap="round"
|
||||||
|
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
||||||
|
|
||||||
|
<line x1="770" y1="380" x2="1120" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
|
<line id="consHeatAni" class="stream" x1="770" y1="380" x2="1120" y2="380" stroke-linecap="round"
|
||||||
|
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
||||||
|
|
||||||
|
<line x1="920" y1="670" x2="1220" y2="670" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
|
<line id="consEVani" class="stream" x1="920" y1="670" x2="1220" y2="670" stroke-linecap="round"
|
||||||
|
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
||||||
|
|
||||||
|
<line x1="920" y1="70" x2="1220" y2="70" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
|
<line id="consEVOGani" class="stream" x1="920" y1="70" x2="1220" y2="70" stroke-linecap="round"
|
||||||
|
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
||||||
|
|
||||||
|
<line x1="100" y1="380" x2="430" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
|
<line id="consGridani" class="stream" x1="100" y1="380" x2="430" y2="380" stroke-linecap="round"
|
||||||
|
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
||||||
|
|
||||||
|
<line x1="180" y1="130" x2="430" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
|
<line id="pvani" class="stream" x1="180" y1="130" x2="430" y2="380" stroke-linecap="round"
|
||||||
|
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
||||||
|
|
||||||
|
<line x1="180" y1="630" x2="430" y2="380" style="stroke:#777;stroke-width:2;stroke-dasharray:1,6;" />
|
||||||
|
<line id="battani" class="stream" x1="180" y1="630" x2="430" y2="380" stroke-linecap="round"
|
||||||
|
stroke-width="0" stroke="gray" stroke-dasharray="1,110" />
|
||||||
|
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
style="position:absolute;top:0;"
|
||||||
|
viewBox="-100 -100 1600 950" width="100%" height="100%" id="realtimeSvg">
|
||||||
|
<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="egIcon" 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="ugIcon" filter="url(#shadow)" transform="translate(52,50),scale(4,4)">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#83a55b;stroke-width:2;stroke-linecap:round;stroke-linejoin:round"
|
||||||
|
d="M 2.977125,13.982235 V 2.973455 h 17.952227 l 0.03597,16.261337"
|
||||||
|
id="path12" />
|
||||||
|
<path fill="#83A55B"
|
||||||
|
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="#83A55B" d="M10.76,8V6.67c0-.45-.17-.66-.52-.67s-.54.22-.54.68V8.34h1.06Z" />
|
||||||
|
<path fill="#83A55B" 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" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#83a55b;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;"
|
||||||
|
d="M 23.96101,19.98372 C 11.24143,20.28899 11.139675,15.0994 -3.106255,14.081835" />
|
||||||
|
</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="pvInfo" class="clickable" transform="translate(330,280)">
|
||||||
|
<animateMotion begin="0.5s" dur="2s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".1,0,.27,1" path="M0 0 L-250 -250" fill="freeze">
|
||||||
|
</animateMotion>
|
||||||
|
<animate id="openDetails" begin="click" attributetype="CSS" attributeName="opacity" from="1"
|
||||||
|
to="1"
|
||||||
|
dur="0.1s" repeatCount="1" calcMode="spline"
|
||||||
|
fill="freeze">
|
||||||
|
</animate>
|
||||||
|
<!--<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>
|
||||||
|
<circle id="closeDetails" fill="transparent" transform="translate(250,124)">
|
||||||
|
<animate begin="click" attributetype="CSS" attributeName="r" from="120" to="0" dur="0.1s"
|
||||||
|
repeatCount="1"
|
||||||
|
fill="freeze" />
|
||||||
|
<animate begin="pvInfo.click" attributeName="r" from="0" to="120" dur="0.1s" repeatCount="1"
|
||||||
|
fill="freeze" />
|
||||||
|
</circle>
|
||||||
|
<!--NON-PV-->
|
||||||
|
<g id="nonPVGroup">
|
||||||
|
<animate begin="pvInfo.click" attributetype="CSS" attributeName="opacity" from="1.0" to="0.0"
|
||||||
|
dur="1s"
|
||||||
|
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
|
||||||
|
<animate begin="closeDetails.click" attributetype="CSS" attributeName="opacity" from="0.0"
|
||||||
|
to="1.0"
|
||||||
|
dur="1s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
|
||||||
|
fill="freeze" />
|
||||||
|
<g transform="translate(330,280), scale(0.90,0.90)" id="heatInfo" class="clickable" onclick="openModal('heater')">
|
||||||
|
<animateMotion begin="0.5s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".1,0,.27,1" path="M0 0 L340 0" fill="freeze"></animateMotion>
|
||||||
|
<animateMotion begin="1.2s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".6,0,.27,1" path="M340 0 L700 0" fill="freeze"></animateMotion>
|
||||||
|
<!--<g
|
||||||
|
filter="url(#glow)">-->
|
||||||
|
<use href="#ElementBG" stroke="#5E2B21" />
|
||||||
|
<path fill="url(#gradient1)" stroke="#5E2B21" stroke-width="4"
|
||||||
|
d="M 99.86386438745993 22.00011880076356 A 78 78 0 1 0 100 22" />
|
||||||
|
<use href="#heatIcon" />
|
||||||
|
<path id="heatArc" fill="none" stroke="#C2614E" stroke-width="30" />
|
||||||
|
<use href="#circGrid6kW" style="stroke:#5E2B21;" />
|
||||||
|
<!--</g>-->
|
||||||
|
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
||||||
|
<textPath id="heatText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
|
||||||
|
<textPath id="heatUp" href="#infoTextPath" startOffset="9%">--°C</textPath>
|
||||||
|
<textPath id="heatDown" href="#infoTextPath" startOffset="36%">--°C</textPath>
|
||||||
|
</text>
|
||||||
|
<use id="heatEco" href="#ecoIcon" style="display:none;" />
|
||||||
|
<use id="heatDefault" href="#alertIcon" style="display:none;" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g transform="translate(330,280), scale(0.90,0.90)" class="clickable" id="CarInfoOG" onclick="openModal('CarOG')">
|
||||||
|
<animateMotion begin="0.5s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".1,0,.27,1" path="M0 0 L340 0" fill="freeze" />
|
||||||
|
<animateMotion id="lastInitAni" begin="1.2s" dur=".7s" repeatCount="1" calcMode="spline"
|
||||||
|
keyTimes="0;1" keySplines=".6,0,.27,1" path="M340 0 L800 -300" fill="freeze" />
|
||||||
|
<!--<g
|
||||||
|
filter="url(#glow)">-->
|
||||||
|
<use href="#ElementBG" stroke="#182C43" />
|
||||||
|
<!--<path
|
||||||
|
filter="url(#fillpartialEV)" fill="#212529" stroke="#642445" stroke-width="4" d="M 99.863863
|
||||||
|
22.00012 A 78 78 0 1 0 100 22" />-->
|
||||||
|
<use href="#carIcon" stroke="#4b71a6" />
|
||||||
|
|
||||||
|
|
||||||
|
<use id="evChargeOG" href="#voltage" transform="translate(167,45),rotate(90),scale(5,5)"
|
||||||
|
style="fill:#cccc00; display:none;" />
|
||||||
|
<path id="evArcOG" fill="none" stroke="#4b71a6" stroke-width="30" />
|
||||||
|
<use href="#circGrid" style="stroke:#182C43;" />
|
||||||
|
<!--</g>-->
|
||||||
|
<use id="evPlugOG" href="#plugCordIcon" style="fill:#4b71a6;display:none;" />
|
||||||
|
<!--<use
|
||||||
|
href="#voltage" style="fill:#888;" transform="scale(3, 3),translate(7,32), rotate(50)" />-->
|
||||||
|
<!--<use
|
||||||
|
href="#gas" style="fill:#888;" transform="scale(0.55, 0.55),translate(210,319), rotate(337)"
|
||||||
|
/>-->
|
||||||
|
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
||||||
|
<textPath id="evTextOG" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
|
||||||
|
<!--<textPath
|
||||||
|
id="evFuelOG" href="#infoTextPath" startOffset="40%">-%</textPath>-->
|
||||||
|
<!--<textPath
|
||||||
|
id="evSOCOG" href="#infoTextPath" startOffset="15%">-%</textPath>-->
|
||||||
|
</text>
|
||||||
|
<!--<use
|
||||||
|
id="evLockOG" href="#lockIcon" style="display:none;" />-->
|
||||||
|
<use id="evEcoOG" href="#ecoIcon" style="display:none;" />
|
||||||
|
<use id="evDefaultOG" href="#plugCordIcon" transform="translate(105,-65),rotate(20)"
|
||||||
|
style="fill:#a53;display:none;" />
|
||||||
|
<use id="evNextTripOG" href="#clock" style="display:none;" />
|
||||||
|
<text dy="160" dx="100" id="evRemText" class="powerTextClass" />
|
||||||
|
</g>
|
||||||
|
<g transform="translate(330,280), scale(0.90,0.90)" class="clickable" id="CarInfo" onclick="openModal('CarEG')">
|
||||||
|
|
||||||
|
<animateMotion begin="0.5s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".1,0,.27,1" path="M0 0 L340 0" fill="freeze" />
|
||||||
|
<animateMotion id="lastInitAni" begin="1.2s" dur=".7s" repeatCount="1" calcMode="spline"
|
||||||
|
keyTimes="0;1" keySplines=".6,0,.27,1" path="M340 0 L800 300" fill="freeze" />
|
||||||
|
<!--<g
|
||||||
|
filter="url(#glow)">-->
|
||||||
|
<use href="#ElementBG" stroke="#1f5a66" />
|
||||||
|
<path filter="url(#fillpartialEV)" fill="#212529" stroke="#1f5a66" stroke-width="4"
|
||||||
|
d="M 99.863863 22.00012 A 78 78 0 1 0 100 22" />
|
||||||
|
<use href="#carIcon" stroke="#60afbf" />
|
||||||
|
|
||||||
|
|
||||||
|
<use id="evCharge" href="#voltage" transform="translate(167,45),rotate(90),scale(5,5)"
|
||||||
|
style="fill:#cccc00; display:none;" />
|
||||||
|
<path id="evArc" fill="none" stroke="#60afbf" stroke-width="30" />
|
||||||
|
<use href="#circGrid" style="stroke:#1f5a66;" />
|
||||||
|
<use id="evPlug" href="#plugCordIcon" style="fill:#60afbf;display:none;" />
|
||||||
|
<!--</g>-->
|
||||||
|
<use href="#voltage" style="fill:#888;" transform="scale(3, 3),translate(7,32), rotate(50)" />
|
||||||
|
<use href="#gas" style="fill:#888;"
|
||||||
|
transform="scale(0.55, 0.55),translate(210,319), rotate(337)" />
|
||||||
|
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
||||||
|
<textPath id="evText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
|
||||||
|
<textPath id="evFuel" href="#infoTextPath" startOffset="40%">--%</textPath>
|
||||||
|
<textPath id="evSOC" href="#infoTextPath" startOffset="15%">--%</textPath>
|
||||||
|
</text>
|
||||||
|
<use id="evLock" href="#lockIcon" style="display:none;" />
|
||||||
|
<use id="evEco" href="#ecoIcon" style="display:none;" />
|
||||||
|
<use id="evDefault" href="#plugCordIcon" transform="translate(105,-65),rotate(20)"
|
||||||
|
style="fill:#a53;display:none;" />
|
||||||
|
<use id="evNextTrip" href="#clock" style="display:none;" />
|
||||||
|
<text dy="160" dx="100" id="evRemText" class="powerTextClass" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g transform="translate(330,280), scale(0.90,0.90)" id="UGInfo">
|
||||||
|
<animateMotion begin="0.5s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".1,0,.27,1" path="M0 0 L340 0" fill="freeze" />
|
||||||
|
<animateMotion begin="1.2s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".6,0,.27,1" path="M340 0 L180 300" fill="freeze" />
|
||||||
|
<!--<g
|
||||||
|
filter="url(#glow)">-->
|
||||||
|
<use href="#ElementBG" stroke="#314619" />
|
||||||
|
<use href="#ugIcon" />
|
||||||
|
<path id="ugArc" fill="none" stroke="#83A55B" stroke-width="30" />
|
||||||
|
<use href="#circGrid" style="stroke:#314619;" />
|
||||||
|
<!--</g>-->
|
||||||
|
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
||||||
|
<textPath id="ugText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g transform="translate(330,280), scale(0.90,0.90)" id="EGInfo">
|
||||||
|
<animateMotion begin="0.5s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".1,0,.27,1" path="M0 0 L340 0" fill="freeze" />
|
||||||
|
<animateMotion begin="1.2s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".6,0,.27,1" path="M340 0 L500 300" fill="freeze" />
|
||||||
|
<!--<g
|
||||||
|
filter="url(#glow)">-->
|
||||||
|
<use href="#ElementBG" stroke="#18423B" />
|
||||||
|
<use href="#egIcon" />
|
||||||
|
<path id="egArc" fill="none" stroke="#70CC9C" stroke-width="30" />
|
||||||
|
<use href="#circGrid" style="stroke:#18423B;" />
|
||||||
|
<!--</g>-->
|
||||||
|
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
||||||
|
<textPath id="egText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
|
||||||
|
</text>
|
||||||
|
<use id="heatEG" transform="translate(120,170)"
|
||||||
|
style='display:none;mix-blend-mode: difference;fill:#70CCBB;' href="#heater" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g transform="translate(330,280), scale(0.70,0.70)" id="waterInfo">
|
||||||
|
<animateMotion begin="0.5s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".1,0,.27,1" path="M0 0 L340 0" fill="freeze" />
|
||||||
|
<animateMotion begin="1.2s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".6,0,.27,1" path="M340 0 L120 -300" fill="freeze" />
|
||||||
|
<!--<g
|
||||||
|
filter="url(#glow)">-->
|
||||||
|
<use href="#ElementBG" stroke="#182C43" />
|
||||||
|
<path filter="url(#fillpartialWater)" fill="#212529" stroke="#182C43" stroke-width="4"
|
||||||
|
d="M 99.863863 22.00012 A 78 78 0 1 0 100 22" />
|
||||||
|
<use href="#water" transform="translate(60,55), scale(0.20,0.20)" fill="#3A6292" />
|
||||||
|
<!--</g>-->
|
||||||
|
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
||||||
|
<textPath id="waterText" href="#powerTextPath" startOffset="25%">--.- cm</textPath>
|
||||||
|
<textPath id="waterTemp" href="#infoTextPath" startOffset="26%">-.- °C</textPath>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g transform="translate(330,280), scale(0.90,0.90)" id="OGInfo">
|
||||||
|
<animateMotion begin="0.5s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".1,0,.27,1" path="M0 0 L340 0" fill="freeze" />
|
||||||
|
<animateMotion begin="1.2s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".6,0,.27,1" path="M340 0 L500 -300" fill="freeze" />
|
||||||
|
<!--<g
|
||||||
|
filter="url(#glow)">-->
|
||||||
|
<use href="#ElementBG" stroke="#18423B" />
|
||||||
|
<use href="#ogIcon" />
|
||||||
|
<path id="ogArc" fill="none" stroke="#70CCBB" stroke-width="30" />
|
||||||
|
<use href="#circGrid" style="stroke:#18423B;" />
|
||||||
|
<!--</g>-->
|
||||||
|
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
||||||
|
<textPath id="ogText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
|
||||||
|
</text>
|
||||||
|
<use id="heatOG" transform="translate(120,165)"
|
||||||
|
style='display:none;mix-blend-mode: difference;fill:#70CCBB;' href="#heater" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g transform="translate(330,280)">
|
||||||
|
<animateMotion begin="0.5s" dur=".7s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".1,0,.27,1" path="M0 0 L340 0" fill="freeze" />
|
||||||
|
<!--<g
|
||||||
|
filter="url(#glow)">-->
|
||||||
|
<use href="#ElementBG" stroke="#1D4154" />
|
||||||
|
<use href="#plugIcon" />
|
||||||
|
<path id="consumerArc" fill="none" stroke="#71afcd" stroke-width="30" />
|
||||||
|
<use href="#circGrid" style="stroke:#1D4154;" />
|
||||||
|
<!--</g>-->
|
||||||
|
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
||||||
|
<textPath id="consumerText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
|
||||||
|
<textPath id="consumerTextAllg" href="#infoTextPath" startOffset="25%">--.-- kW</textPath>
|
||||||
|
<!--<textPath id="consumerTextEG" href="#infoTextPath" startOffset="35%">.- kW</textPath>
|
||||||
|
<textPath id="consumerTextUG" href="#infoTextPath" startOffset="55%">-.- kW</textPath> -->
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(330,280)">
|
||||||
|
<animateMotion begin="0.5s" dur="1.5s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".1,0,.27,1" path="M0 0 L-250 250" fill="freeze" />
|
||||||
|
<!--<g
|
||||||
|
filter="url(#glow)">-->
|
||||||
|
<use href="#ElementBG" stroke="#25481C" />
|
||||||
|
<path id="batArc" fill="none" stroke="#6cbe58" stroke-width="30" />
|
||||||
|
<path filter="url(#fillpartialBat)" fill="#212529" stroke="#25481C" stroke-width="4"
|
||||||
|
d="M 99.863863 22.00012 A 78 78 0 1 0 100 22" />
|
||||||
|
<use href="#battIcon" />
|
||||||
|
<use href="#circGrid" style="stroke:#25481C;" />
|
||||||
|
<use id="batLim" href="#clock" style="" transform="translate(4,40)" />
|
||||||
|
<!--</g>-->
|
||||||
|
<text id="batLimText" filter="url(#shadowMiddle)" class="infoTextClass"
|
||||||
|
transform="translate(103,132)"></text>
|
||||||
|
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
||||||
|
<textPath id="batText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
|
||||||
|
<textPath id="batSOC" href="#infoTextPath" startOffset="26%">--.- %</textPath>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(330,280)">
|
||||||
|
<animateMotion begin="0.5s" dur="1s" repeatCount="1" calcMode="spline" keyTimes="0;1"
|
||||||
|
keySplines=".1,0,.27,1" path="M0 0 L-330 0" fill="freeze" />
|
||||||
|
<!--<g
|
||||||
|
filter="url(#glow)">-->
|
||||||
|
<use href="#ElementBG" stroke="#2D2D34" />
|
||||||
|
<path id="gridArc" fill="none" stroke="#808090" stroke-width="30" />
|
||||||
|
<use href="#circGrid" style="stroke:#2D2D34;" />
|
||||||
|
<!--</g>-->
|
||||||
|
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
||||||
|
<textPath id="gridText" href="#powerTextPath" startOffset="15%">--.-- kW</textPath>
|
||||||
|
<textPath id="il1txt" href="#infoTextPath" startOffset="10%">--.- A</textPath>
|
||||||
|
<textPath id="il2txt" href="#infoTextPath" startOffset="25%">--.- A</textPath>
|
||||||
|
<textPath id="il3txt" href="#infoTextPath" startOffset="40%">--.- A</textPath>
|
||||||
|
</text>
|
||||||
|
<use href="#gridIcon" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g transform="translate(330,280), scale(1.1,1.1)" class="tooltip-trigger"
|
||||||
|
data-tooltip-text="The amazing pink box">
|
||||||
|
<!--<g
|
||||||
|
filter="url(#glow)">-->
|
||||||
|
<use href="#ElementBG" stroke="#2D2D34" />
|
||||||
|
<!--</g>-->
|
||||||
|
<text filter="url(#shadowMiddle)" class="powerTextClass">
|
||||||
|
<textPath id="genText" href="#powerTextPath" startOffset="22%">Autarkie: </textPath>
|
||||||
|
<textPath id="genInfoText" href="#infoTextPath" startOffset="25%"></textPath>
|
||||||
|
|
||||||
|
</text>
|
||||||
|
<use href="#inverterIcon" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g id="pvDetail" opacity="0" transform="scale(0.1,0.1)">
|
||||||
|
<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_pv20P" 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_pv21P" 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>
|
||||||
|
|
||||||
|
<g id="tooltip" visibility="hidden">
|
||||||
|
<rect x="2" y="2" width="200" height="60" fill="black" opacity="0.4" rx="2" ry="2" />
|
||||||
|
<rect width="200" height="60" fill="white" rx="2" ry="2" />
|
||||||
|
<text x="4" y="6">Tooltip</text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
354
authServer.php
Normal file
@ -0,0 +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));
|
||||||
|
}
|
||||||
15657
css/adminlte.css
Normal file
7
css/adminlte.min.css
vendored
Normal file
15603
css/adminlte.rtl.css
Normal file
7
css/adminlte.rtl.min.css
vendored
Normal file
638
css/apexcharts.css
Normal file
@ -0,0 +1,638 @@
|
|||||||
|
@keyframes opaque {
|
||||||
|
0% {
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes resizeanim {
|
||||||
|
0%,to {
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-canvas {
|
||||||
|
position: relative;
|
||||||
|
user-select: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-canvas ::-webkit-scrollbar {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
width: 6px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-canvas ::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: rgba(0,0,0,.5);
|
||||||
|
box-shadow: 0 0 1px rgba(255,255,255,.5);
|
||||||
|
-webkit-box-shadow: 0 0 1px rgba(255,255,255,.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-inner {
|
||||||
|
position: relative
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-text tspan {
|
||||||
|
font-family: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-mouseover-inactive {
|
||||||
|
transition: .15s ease all;
|
||||||
|
opacity: .2
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-legend-text {
|
||||||
|
padding-left: 15px;
|
||||||
|
margin-left: -15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-series-collapsed {
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip {
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 2px 2px 6px -4px #999;
|
||||||
|
cursor: default;
|
||||||
|
font-size: 14px;
|
||||||
|
left: 62px;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
z-index: 12;
|
||||||
|
transition: .15s ease all
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip.apexcharts-active {
|
||||||
|
opacity: 1;
|
||||||
|
transition: .15s ease all
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip.apexcharts-theme-light {
|
||||||
|
border: 1px solid #e3e3e3;
|
||||||
|
background: rgba(255,255,255,.96)
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip.apexcharts-theme-dark {
|
||||||
|
color: #fff;
|
||||||
|
background: rgba(30,30,30,.8)
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip * {
|
||||||
|
font-family: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-title {
|
||||||
|
padding: 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
margin-bottom: 4px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip.apexcharts-theme-light .apexcharts-tooltip-title {
|
||||||
|
background: #eceff1;
|
||||||
|
border-bottom: 1px solid #ddd
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip.apexcharts-theme-dark .apexcharts-tooltip-title {
|
||||||
|
background: rgba(0,0,0,.7);
|
||||||
|
border-bottom: 1px solid #333
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-text-goals-value,.apexcharts-tooltip-text-y-value,.apexcharts-tooltip-text-z-value {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 5px;
|
||||||
|
font-weight: 600
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-text-goals-label:empty,.apexcharts-tooltip-text-goals-value:empty,.apexcharts-tooltip-text-y-label:empty,.apexcharts-tooltip-text-y-value:empty,.apexcharts-tooltip-text-z-value:empty,.apexcharts-tooltip-title:empty {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-text-goals-label,.apexcharts-tooltip-text-goals-value {
|
||||||
|
padding: 6px 0 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-goals-group,.apexcharts-tooltip-text-goals-label,.apexcharts-tooltip-text-goals-value {
|
||||||
|
display: flex
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-text-goals-label:not(:empty),.apexcharts-tooltip-text-goals-value:not(:empty) {
|
||||||
|
margin-top: -6px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-marker {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
margin-right: 10px;
|
||||||
|
border-radius: 50%
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-series-group {
|
||||||
|
padding: 0 10px;
|
||||||
|
display: none;
|
||||||
|
text-align: left;
|
||||||
|
justify-content: left;
|
||||||
|
align-items: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-series-group.apexcharts-active .apexcharts-tooltip-marker {
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-series-group.apexcharts-active,.apexcharts-tooltip-series-group:last-child {
|
||||||
|
padding-bottom: 4px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-series-group-hidden {
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
line-height: 0;
|
||||||
|
padding: 0!important
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-y-group {
|
||||||
|
padding: 6px 0 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-custom-tooltip,.apexcharts-tooltip-box {
|
||||||
|
padding: 4px 8px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-boxPlot {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-box>div {
|
||||||
|
margin: 4px 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-box span.value {
|
||||||
|
font-weight: 700
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-rangebar {
|
||||||
|
padding: 5px 8px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-rangebar .category {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #777
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-tooltip-rangebar .series-name {
|
||||||
|
font-weight: 700;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip,.apexcharts-yaxistooltip {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
color: #373d3f;
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 2px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
background: #eceff1;
|
||||||
|
border: 1px solid #90a4ae
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip {
|
||||||
|
padding: 9px 10px;
|
||||||
|
transition: .15s ease all
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip.apexcharts-theme-dark {
|
||||||
|
background: rgba(0,0,0,.7);
|
||||||
|
border: 1px solid rgba(0,0,0,.5);
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip:after,.apexcharts-xaxistooltip:before {
|
||||||
|
left: 50%;
|
||||||
|
border: solid transparent;
|
||||||
|
content: " ";
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip:after {
|
||||||
|
border-color: transparent;
|
||||||
|
border-width: 6px;
|
||||||
|
margin-left: -6px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip:before {
|
||||||
|
border-color: transparent;
|
||||||
|
border-width: 7px;
|
||||||
|
margin-left: -7px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip-bottom:after,.apexcharts-xaxistooltip-bottom:before {
|
||||||
|
bottom: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip-top:after,.apexcharts-xaxistooltip-top:before {
|
||||||
|
top: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip-bottom:after {
|
||||||
|
border-bottom-color: #eceff1
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip-bottom:before {
|
||||||
|
border-bottom-color: #90a4ae
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:after,.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:before {
|
||||||
|
border-bottom-color: rgba(0,0,0,.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip-top:after {
|
||||||
|
border-top-color: #eceff1
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip-top:before {
|
||||||
|
border-top-color: #90a4ae
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip-top.apexcharts-theme-dark:after,.apexcharts-xaxistooltip-top.apexcharts-theme-dark:before {
|
||||||
|
border-top-color: rgba(0,0,0,.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip.apexcharts-active {
|
||||||
|
opacity: 1;
|
||||||
|
transition: .15s ease all
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip {
|
||||||
|
padding: 4px 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip.apexcharts-theme-dark {
|
||||||
|
background: rgba(0,0,0,.7);
|
||||||
|
border: 1px solid rgba(0,0,0,.5);
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip:after,.apexcharts-yaxistooltip:before {
|
||||||
|
top: 50%;
|
||||||
|
border: solid transparent;
|
||||||
|
content: " ";
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip:after {
|
||||||
|
border-color: transparent;
|
||||||
|
border-width: 6px;
|
||||||
|
margin-top: -6px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip:before {
|
||||||
|
border-color: transparent;
|
||||||
|
border-width: 7px;
|
||||||
|
margin-top: -7px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip-left:after,.apexcharts-yaxistooltip-left:before {
|
||||||
|
left: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip-right:after,.apexcharts-yaxistooltip-right:before {
|
||||||
|
right: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip-left:after {
|
||||||
|
border-left-color: #eceff1
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip-left:before {
|
||||||
|
border-left-color: #90a4ae
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip-left.apexcharts-theme-dark:after,.apexcharts-yaxistooltip-left.apexcharts-theme-dark:before {
|
||||||
|
border-left-color: rgba(0,0,0,.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip-right:after {
|
||||||
|
border-right-color: #eceff1
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip-right:before {
|
||||||
|
border-right-color: #90a4ae
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip-right.apexcharts-theme-dark:after,.apexcharts-yaxistooltip-right.apexcharts-theme-dark:before {
|
||||||
|
border-right-color: rgba(0,0,0,.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip.apexcharts-active {
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-yaxistooltip-hidden {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xcrosshairs,.apexcharts-ycrosshairs {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
transition: .15s ease all
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-xcrosshairs.apexcharts-active,.apexcharts-ycrosshairs.apexcharts-active {
|
||||||
|
opacity: 1;
|
||||||
|
transition: .15s ease all
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-ycrosshairs-hidden {
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-selection-rect {
|
||||||
|
cursor: move
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg_select_boundingRect,.svg_select_points_rot {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-selection-rect+g .svg_select_boundingRect,.apexcharts-selection-rect+g .svg_select_points_rot {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-selection-rect+g .svg_select_points_l,.apexcharts-selection-rect+g .svg_select_points_r {
|
||||||
|
cursor: ew-resize;
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg_select_points {
|
||||||
|
fill: #efefef;
|
||||||
|
stroke: #333;
|
||||||
|
rx: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-svg.apexcharts-zoomable.hovering-zoom {
|
||||||
|
cursor: crosshair
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-svg.apexcharts-zoomable.hovering-pan {
|
||||||
|
cursor: move
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-menu-icon,.apexcharts-pan-icon,.apexcharts-reset-icon,.apexcharts-selection-icon,.apexcharts-toolbar-custom-icon,.apexcharts-zoom-icon,.apexcharts-zoomin-icon,.apexcharts-zoomout-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 24px;
|
||||||
|
color: #6e8192;
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-menu-icon svg,.apexcharts-reset-icon svg,.apexcharts-zoom-icon svg,.apexcharts-zoomin-icon svg,.apexcharts-zoomout-icon svg {
|
||||||
|
fill: #6e8192
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-selection-icon svg {
|
||||||
|
fill: #444;
|
||||||
|
transform: scale(.76)
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-theme-dark .apexcharts-menu-icon svg,.apexcharts-theme-dark .apexcharts-pan-icon svg,.apexcharts-theme-dark .apexcharts-reset-icon svg,.apexcharts-theme-dark .apexcharts-selection-icon svg,.apexcharts-theme-dark .apexcharts-toolbar-custom-icon svg,.apexcharts-theme-dark .apexcharts-zoom-icon svg,.apexcharts-theme-dark .apexcharts-zoomin-icon svg,.apexcharts-theme-dark .apexcharts-zoomout-icon svg {
|
||||||
|
fill: #f3f4f5
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-canvas .apexcharts-reset-zoom-icon.apexcharts-selected svg,.apexcharts-canvas .apexcharts-selection-icon.apexcharts-selected svg,.apexcharts-canvas .apexcharts-zoom-icon.apexcharts-selected svg {
|
||||||
|
fill: #008ffb
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-theme-light .apexcharts-menu-icon:hover svg,.apexcharts-theme-light .apexcharts-reset-icon:hover svg,.apexcharts-theme-light .apexcharts-selection-icon:not(.apexcharts-selected):hover svg,.apexcharts-theme-light .apexcharts-zoom-icon:not(.apexcharts-selected):hover svg,.apexcharts-theme-light .apexcharts-zoomin-icon:hover svg,.apexcharts-theme-light .apexcharts-zoomout-icon:hover svg {
|
||||||
|
fill: #333
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-menu-icon,.apexcharts-selection-icon {
|
||||||
|
position: relative
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-reset-icon {
|
||||||
|
margin-left: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-menu-icon,.apexcharts-reset-icon,.apexcharts-zoom-icon {
|
||||||
|
transform: scale(.85)
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-zoomin-icon,.apexcharts-zoomout-icon {
|
||||||
|
transform: scale(.7)
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-zoomout-icon {
|
||||||
|
margin-right: 3px
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-pan-icon {
|
||||||
|
transform: scale(.62);
|
||||||
|
position: relative;
|
||||||
|
left: 1px;
|
||||||
|
top: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-pan-icon svg {
|
||||||
|
fill: #fff;
|
||||||
|
stroke: #6e8192;
|
||||||
|
stroke-width: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-pan-icon.apexcharts-selected svg {
|
||||||
|
stroke: #008ffb
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-pan-icon:not(.apexcharts-selected):hover svg {
|
||||||
|
stroke: #333
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-toolbar {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 11;
|
||||||
|
max-width: 176px;
|
||||||
|
text-align: right;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0 6px 2px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-menu {
|
||||||
|
background: #fff;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 3px;
|
||||||
|
right: 10px;
|
||||||
|
opacity: 0;
|
||||||
|
min-width: 110px;
|
||||||
|
transition: .15s ease all;
|
||||||
|
pointer-events: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-menu.apexcharts-menu-open {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: all;
|
||||||
|
transition: .15s ease all
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-menu-item {
|
||||||
|
padding: 6px 7px;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-theme-light .apexcharts-menu-item:hover {
|
||||||
|
background: #eee
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-theme-dark .apexcharts-menu {
|
||||||
|
background: rgba(0,0,0,.7);
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width:768px) {
|
||||||
|
.apexcharts-canvas:hover .apexcharts-toolbar {
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-canvas .apexcharts-element-hidden,.apexcharts-datalabel.apexcharts-element-hidden,.apexcharts-hide .apexcharts-series-points {
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-datalabel,.apexcharts-datalabel-label,.apexcharts-datalabel-value,.apexcharts-datalabels,.apexcharts-pie-label {
|
||||||
|
cursor: default;
|
||||||
|
pointer-events: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-pie-label-delay {
|
||||||
|
opacity: 0;
|
||||||
|
animation-name: opaque;
|
||||||
|
animation-duration: .3s;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
animation-timing-function: ease
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-legend {
|
||||||
|
display: flex;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
.apexcharts-legend.apx-legend-position-bottom, .apexcharts-legend.apx-legend-position-top {
|
||||||
|
flex-wrap: wrap
|
||||||
|
}
|
||||||
|
.apexcharts-legend.apx-legend-position-right, .apexcharts-legend.apx-legend-position-left {
|
||||||
|
flex-direction: column;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.apexcharts-legend.apx-legend-position-bottom.apexcharts-align-left, .apexcharts-legend.apx-legend-position-top.apexcharts-align-left, .apexcharts-legend.apx-legend-position-right, .apexcharts-legend.apx-legend-position-left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
.apexcharts-legend.apx-legend-position-bottom.apexcharts-align-center, .apexcharts-legend.apx-legend-position-top.apexcharts-align-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.apexcharts-legend.apx-legend-position-bottom.apexcharts-align-right, .apexcharts-legend.apx-legend-position-top.apexcharts-align-right {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
.apexcharts-legend-series {
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
.apexcharts-legend.apx-legend-position-bottom .apexcharts-legend-series, .apexcharts-legend.apx-legend-position-top .apexcharts-legend-series{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.apexcharts-legend-text {
|
||||||
|
position: relative;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.apexcharts-legend-text *, .apexcharts-legend-marker * {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.apexcharts-legend-marker {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 3px;
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-legend.apexcharts-align-right .apexcharts-legend-series, .apexcharts-legend.apexcharts-align-left .apexcharts-legend-series{
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.apexcharts-legend-series.apexcharts-no-click {
|
||||||
|
cursor: auto;
|
||||||
|
}
|
||||||
|
.apexcharts-legend .apexcharts-hidden-zero-series, .apexcharts-legend .apexcharts-hidden-null-series {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.apexcharts-inactive-legend {
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-annotation-rect,.apexcharts-area-series .apexcharts-area,.apexcharts-area-series .apexcharts-series-markers .apexcharts-marker.no-pointer-events,.apexcharts-gridline,.apexcharts-line,.apexcharts-line-series .apexcharts-series-markers .apexcharts-marker.no-pointer-events,.apexcharts-point-annotation-label,.apexcharts-radar-series path,.apexcharts-radar-series polygon,.apexcharts-toolbar svg,.apexcharts-tooltip .apexcharts-marker,.apexcharts-xaxis-annotation-label,.apexcharts-yaxis-annotation-label,.apexcharts-zoom-rect {
|
||||||
|
pointer-events: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.apexcharts-marker {
|
||||||
|
transition: .15s ease all
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-triggers {
|
||||||
|
animation: 1ms resizeanim;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
.contract-trigger:before,.resize-triggers,.resize-triggers>div {
|
||||||
|
content: " ";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-triggers>div {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background: #eee;
|
||||||
|
overflow: auto
|
||||||
|
}
|
||||||
|
|
||||||
|
.contract-trigger:before {
|
||||||
|
overflow: hidden;
|
||||||
|
width: 200%;
|
||||||
|
height: 200%
|
||||||
|
}
|
||||||
5
css/bootstrap-icons.min.css
vendored
Normal file
BIN
css/bootstrap-icons.woff
Normal file
BIN
css/bootstrap-icons.woff2
Normal file
1
css/jsvectormap.min.css
vendored
Normal file
@ -0,0 +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}}
|
||||||
9
css/overlayscrollbars.min.css
vendored
Normal file
13
css/solar.css
Normal file
@ -0,0 +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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1,181 +0,0 @@
|
|||||||
-- ============================================================================
|
|
||||||
-- Somfy Tahoma Datenbank Schema
|
|
||||||
-- Normalisierte Struktur für Aktoren, Sensoren und ihre Parameter
|
|
||||||
-- ============================================================================
|
|
||||||
|
|
||||||
-- Datenbank erstellen (falls noch nicht vorhanden)
|
|
||||||
-- CREATE DATABASE IF NOT EXISTS EnergyFlow CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
|
|
||||||
-- USE EnergyFlow;
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
-- HAUPTTABELLEN
|
|
||||||
-- ============================================================================
|
|
||||||
|
|
||||||
-- Tabelle: actors
|
|
||||||
-- Speichert alle Aktoren (Geräte mit Steuerungsfunktion)
|
|
||||||
CREATE TABLE IF NOT EXISTS `actors` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`type` varchar(50) NOT NULL COMMENT 'Gerätetyp z.B. RollerShutter',
|
|
||||||
`name` varchar(70) NOT NULL COMMENT 'Name des Geräts',
|
|
||||||
`parameters` text DEFAULT NULL COMMENT 'Zusätzliche Meta-Informationen als JSON',
|
|
||||||
`url` varchar(100) NOT NULL COMMENT 'Tahoma Device URL',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `url` (`url`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
|
||||||
|
|
||||||
-- Tabelle: sensors
|
|
||||||
-- Speichert alle Sensoren (Geräte die Werte melden)
|
|
||||||
CREATE TABLE IF NOT EXISTS `sensors` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`type` varchar(50) NOT NULL COMMENT 'Sensortyp z.B. TemperatureSensor',
|
|
||||||
`name` varchar(70) NOT NULL COMMENT 'Name des Sensors',
|
|
||||||
`parameters` text DEFAULT NULL COMMENT 'Zusätzliche Meta-Informationen als JSON',
|
|
||||||
`url` varchar(100) NOT NULL COMMENT 'Tahoma Device URL',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `url` (`url`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
-- AKTOR-BEZOGENE TABELLEN
|
|
||||||
-- ============================================================================
|
|
||||||
|
|
||||||
-- Tabelle: actor_commands
|
|
||||||
-- Speichert alle verfügbaren Commands für jeden Aktor
|
|
||||||
CREATE TABLE IF NOT EXISTS `actor_commands` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`actor_id` int(11) NOT NULL COMMENT 'Referenz zum Aktor',
|
|
||||||
`command_name` varchar(100) NOT NULL COMMENT 'Name des Commands z.B. setPosition, open, close',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `actor_id` (`actor_id`),
|
|
||||||
CONSTRAINT `fk_actor_commands_actor`
|
|
||||||
FOREIGN KEY (`actor_id`) REFERENCES `actors`(`id`)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
|
||||||
|
|
||||||
-- Tabelle: command_parameters
|
|
||||||
-- Speichert die Parameter für jeden Command
|
|
||||||
CREATE TABLE IF NOT EXISTS `command_parameters` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`command_id` int(11) NOT NULL COMMENT 'Referenz zum Command',
|
|
||||||
`parameter_name` varchar(100) NOT NULL COMMENT 'Name des Parameters z.B. position',
|
|
||||||
`parameter_type` varchar(50) DEFAULT NULL COMMENT 'Datentyp z.B. integer, string',
|
|
||||||
`min_value` decimal(10,2) DEFAULT NULL COMMENT 'Minimaler Wert (falls numerisch)',
|
|
||||||
`max_value` decimal(10,2) DEFAULT NULL COMMENT 'Maximaler Wert (falls numerisch)',
|
|
||||||
`possible_values` text DEFAULT NULL COMMENT 'JSON Array mit möglichen Werten (für Enums)',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `command_id` (`command_id`),
|
|
||||||
CONSTRAINT `fk_command_parameters_command`
|
|
||||||
FOREIGN KEY (`command_id`) REFERENCES `actor_commands`(`id`)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
-- SENSOR-BEZOGENE TABELLEN
|
|
||||||
-- ============================================================================
|
|
||||||
|
|
||||||
-- Tabelle: sensor_states
|
|
||||||
-- Speichert alle verfügbaren States für jeden Sensor
|
|
||||||
CREATE TABLE IF NOT EXISTS `sensor_states` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`sensor_id` int(11) NOT NULL COMMENT 'Referenz zum Sensor',
|
|
||||||
`state_name` varchar(100) NOT NULL COMMENT 'Name des State z.B. core:TemperatureState',
|
|
||||||
`state_type` int(11) DEFAULT NULL COMMENT 'State-Typ Code aus Tahoma API',
|
|
||||||
`current_value` varchar(255) DEFAULT NULL COMMENT 'Aktueller Wert des State',
|
|
||||||
`unit` varchar(20) DEFAULT NULL COMMENT 'Einheit z.B. °C, %, lux',
|
|
||||||
`last_updated` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `sensor_id` (`sensor_id`),
|
|
||||||
CONSTRAINT `fk_sensor_states_sensor`
|
|
||||||
FOREIGN KEY (`sensor_id`) REFERENCES `sensors`(`id`)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
-- GEMEINSAME TABELLE FÜR ACTOR STATES (optional)
|
|
||||||
-- ============================================================================
|
|
||||||
|
|
||||||
-- Tabelle: actor_states
|
|
||||||
-- Speichert die aktuellen States von Aktoren (z.B. aktuelle Position)
|
|
||||||
CREATE TABLE IF NOT EXISTS `actor_states` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`actor_id` int(11) NOT NULL COMMENT 'Referenz zum Aktor',
|
|
||||||
`state_name` varchar(100) NOT NULL COMMENT 'Name des State z.B. core:ClosureState',
|
|
||||||
`state_type` int(11) DEFAULT NULL COMMENT 'State-Typ Code aus Tahoma API',
|
|
||||||
`current_value` varchar(255) DEFAULT NULL COMMENT 'Aktueller Wert des State',
|
|
||||||
`unit` varchar(20) DEFAULT NULL COMMENT 'Einheit falls vorhanden',
|
|
||||||
`last_updated` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `actor_id` (`actor_id`),
|
|
||||||
CONSTRAINT `fk_actor_states_actor`
|
|
||||||
FOREIGN KEY (`actor_id`) REFERENCES `actors`(`id`)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
-- INDIZES FÜR PERFORMANCE
|
|
||||||
-- ============================================================================
|
|
||||||
|
|
||||||
-- Zusätzliche Indizes für häufige Queries
|
|
||||||
CREATE INDEX idx_actors_type ON actors(type);
|
|
||||||
CREATE INDEX idx_sensors_type ON sensors(type);
|
|
||||||
CREATE INDEX idx_actor_commands_name ON actor_commands(command_name);
|
|
||||||
CREATE INDEX idx_sensor_states_name ON sensor_states(state_name);
|
|
||||||
CREATE INDEX idx_actor_states_name ON actor_states(state_name);
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
-- VIEWS (optional - für einfachere Queries)
|
|
||||||
-- ============================================================================
|
|
||||||
|
|
||||||
-- View: Alle Aktoren mit ihren Commands
|
|
||||||
CREATE OR REPLACE VIEW view_actors_with_commands AS
|
|
||||||
SELECT
|
|
||||||
a.id as actor_id,
|
|
||||||
a.name as actor_name,
|
|
||||||
a.type as actor_type,
|
|
||||||
a.url as actor_url,
|
|
||||||
ac.id as command_id,
|
|
||||||
ac.command_name,
|
|
||||||
cp.parameter_name,
|
|
||||||
cp.parameter_type,
|
|
||||||
cp.min_value,
|
|
||||||
cp.max_value,
|
|
||||||
cp.possible_values
|
|
||||||
FROM actors a
|
|
||||||
LEFT JOIN actor_commands ac ON a.id = ac.actor_id
|
|
||||||
LEFT JOIN command_parameters cp ON ac.id = cp.command_id
|
|
||||||
ORDER BY a.id, ac.id, cp.id;
|
|
||||||
|
|
||||||
-- View: Alle Sensoren mit ihren States
|
|
||||||
CREATE OR REPLACE VIEW view_sensors_with_states AS
|
|
||||||
SELECT
|
|
||||||
s.id as sensor_id,
|
|
||||||
s.name as sensor_name,
|
|
||||||
s.type as sensor_type,
|
|
||||||
s.url as sensor_url,
|
|
||||||
ss.state_name,
|
|
||||||
ss.state_type,
|
|
||||||
ss.current_value,
|
|
||||||
ss.unit,
|
|
||||||
ss.last_updated
|
|
||||||
FROM sensors s
|
|
||||||
LEFT JOIN sensor_states ss ON s.id = ss.sensor_id
|
|
||||||
ORDER BY s.id, ss.id;
|
|
||||||
|
|
||||||
-- View: Übersicht aller Geräte
|
|
||||||
CREATE OR REPLACE VIEW view_all_devices AS
|
|
||||||
SELECT
|
|
||||||
'actor' as device_category,
|
|
||||||
id,
|
|
||||||
type,
|
|
||||||
name,
|
|
||||||
url
|
|
||||||
FROM actors
|
|
||||||
UNION ALL
|
|
||||||
SELECT
|
|
||||||
'sensor' as device_category,
|
|
||||||
id,
|
|
||||||
type,
|
|
||||||
name,
|
|
||||||
url
|
|
||||||
FROM sensors
|
|
||||||
ORDER BY device_category, name;
|
|
||||||
52
helper.php
Normal file
@ -0,0 +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;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
143
index.php
Normal file
@ -0,0 +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;
|
||||||
|
}
|
||||||
2
js/Sortable.min.js
vendored
Normal file
1191
js/adminlte.js
Normal file
1
js/adminlte.js.map
Normal file
7
js/adminlte.min.js
vendored
Normal file
1
js/adminlte.min.js.map
Normal file
14
js/apexcharts.min.js
vendored
Normal file
149
js/auth.js
Normal file
@ -0,0 +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 += 'µsoft=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;
|
||||||
|
}
|
||||||
BIN
js/bootstrap-5-modal-dynamic-master.zip
Normal file
7
js/bootstrap.min.js
vendored
Normal file
14
js/chart.min.js
vendored
Normal file
7
js/chartjs-adapter-luxon.js
Normal file
@ -0,0 +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()}})}));
|
||||||