Version von testing eingefügt, scroll liste entfernt undkleine Bugsbehoben
This commit is contained in:
+25
-55
@@ -1,67 +1,37 @@
|
|||||||
# Manager_1
|
# Energy_Pie
|
||||||
Beschreibung des Moduls.
|
|
||||||
|
|
||||||
### Inhaltsverzeichnis
|
IP-Symcon-Modul zur Darstellung von Energieverbrauch und Eigenverbrauch in der Kachelvisualisierung.
|
||||||
|
|
||||||
1. [Funktionsumfang](#1-funktionsumfang)
|
## Funktionen
|
||||||
2. [Voraussetzungen](#2-voraussetzungen)
|
|
||||||
3. [Software-Installation](#3-software-installation)
|
|
||||||
4. [Einrichten der Instanzen in IP-Symcon](#4-einrichten-der-instanzen-in-ip-symcon)
|
|
||||||
5. [Statusvariablen und Profile](#5-statusvariablen-und-profile)
|
|
||||||
6. [WebFront](#6-webfront)
|
|
||||||
7. [PHP-Befehlsreferenz](#7-php-befehlsreferenz)
|
|
||||||
|
|
||||||
### 1. Funktionsumfang
|
Das Modul zeigt folgende Werte an:
|
||||||
|
|
||||||
*
|
- Produktion
|
||||||
|
- Hausverbrauch
|
||||||
|
- Netzbezug
|
||||||
|
- Einspeisung
|
||||||
|
- Eigenverbrauchsquote
|
||||||
|
- Autarkiegrad
|
||||||
|
|
||||||
### 2. Voraussetzungen
|
Die Darstellung erfolgt mit zwei Kreisdiagrammen.
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
- IP-Symcon ab Version 7.1
|
- IP-Symcon ab Version 7.1
|
||||||
|
- Aktivierte Archivierung der verwendeten Energiezähler
|
||||||
|
- Energiezähler als fortlaufende kWh-Zähler
|
||||||
|
|
||||||
### 3. Software-Installation
|
## Konfiguration
|
||||||
|
|
||||||
* Über den Module Store das 'Manager_1'-Modul installieren.
|
Folgende Variablen müssen ausgewählt werden:
|
||||||
* Alternativ über das Module Control folgende URL hinzufügen
|
|
||||||
|
|
||||||
### 4. Einrichten der Instanzen in IP-Symcon
|
| Einstellung | Beschreibung |
|
||||||
|
|---|---|
|
||||||
|
| Produktion | Gesamte produzierte Energie in kWh |
|
||||||
|
| Einspeisung | Ins Netz eingespeiste Energie in kWh |
|
||||||
|
| Netzbezug | Aus dem Netz bezogene Energie in kWh |
|
||||||
|
|
||||||
Unter 'Instanz hinzufügen' kann das 'Manager_1'-Modul mithilfe des Schnellfilters gefunden werden.
|
Der Hausverbrauch wird automatisch berechnet:
|
||||||
- Weitere Informationen zum Hinzufügen von Instanzen in der [Dokumentation der Instanzen](https://www.symcon.de/service/dokumentation/konzepte/instanzen/#Instanz_hinzufügen)
|
|
||||||
|
|
||||||
__Konfigurationsseite__:
|
```text
|
||||||
|
Hausverbrauch = Produktion - Einspeisung + Netzbezug
|
||||||
Name | Beschreibung
|
|
||||||
-------- | ------------------
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
||||||
### 5. Statusvariablen und Profile
|
|
||||||
|
|
||||||
Die Statusvariablen/Kategorien werden automatisch angelegt. Das Löschen einzelner kann zu Fehlfunktionen führen.
|
|
||||||
|
|
||||||
#### Statusvariablen
|
|
||||||
|
|
||||||
Name | Typ | Beschreibung
|
|
||||||
------ | ------- | ------------
|
|
||||||
| |
|
|
||||||
| |
|
|
||||||
|
|
||||||
#### Profile
|
|
||||||
|
|
||||||
Name | Typ
|
|
||||||
------ | -------
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
||||||
### 6. WebFront
|
|
||||||
|
|
||||||
Die Funktionalität, die das Modul im WebFront bietet.
|
|
||||||
|
|
||||||
### 7. PHP-Befehlsreferenz
|
|
||||||
|
|
||||||
`boolean GEF_BeispielFunktion(integer $InstanzID);`
|
|
||||||
Erklärung der Funktion.
|
|
||||||
|
|
||||||
Beispiel:
|
|
||||||
`GEF_BeispielFunktion(12345);`
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "type": "SelectVariable", "name": "VarProduction", "caption": "Produktion (kWh)" },
|
{ "type": "SelectVariable", "name": "VarProduction", "caption": "Produktion (kWh)" },
|
||||||
{ "type": "SelectVariable", "name": "VarConsumption", "caption": "Verbrauch (kWh)" },
|
|
||||||
{ "type": "SelectVariable", "name": "VarFeedIn", "caption": "Einspeisung (kWh)" },
|
{ "type": "SelectVariable", "name": "VarFeedIn", "caption": "Einspeisung (kWh)" },
|
||||||
{ "type": "SelectVariable", "name": "VarGrid", "caption": "Bezug Netz (kWh)" }
|
{ "type": "SelectVariable", "name": "VarGrid", "caption": "Bezug Netz (kWh)" }
|
||||||
]
|
]
|
||||||
|
|||||||
+14
-15
@@ -37,14 +37,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@media (max-width:720px){
|
|
||||||
#grid{grid-template-columns:1fr}
|
|
||||||
}
|
|
||||||
|
|
||||||
#wrap{
|
#wrap{
|
||||||
position:relative;
|
position:relative;
|
||||||
overflow:hidden;
|
overflow:hidden;
|
||||||
min-height:100vh;
|
overscroll-behavior:none;
|
||||||
|
touch-action:none;
|
||||||
|
box-sizing:border-box;
|
||||||
background:#121216;
|
background:#121216;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,13 +124,13 @@ function render(data){
|
|||||||
const e = new Date(data.tEnd * 1000 - 1000);
|
const e = new Date(data.tEnd * 1000 - 1000);
|
||||||
|
|
||||||
if (data.range === 'day')
|
if (data.range === 'day')
|
||||||
elPeriod.textContent = `Zeitraum: ${fmt(s)}`;
|
elPeriod.textContent = `Tag: ${fmt(s)}`;
|
||||||
else if (data.range === 'week')
|
else if (data.range === 'week')
|
||||||
elPeriod.textContent = `Zeitraum: Woche ${isoWeek(s)}`;
|
elPeriod.textContent = `Woche: ${fmt(s)} - ${fmt(e)}`;
|
||||||
else if (data.range === 'month')
|
else if (data.range === 'month')
|
||||||
elPeriod.textContent = `Zeitraum: ${monthName(s.getMonth())} ${s.getFullYear()}`;
|
elPeriod.textContent = `Monat: ${monthName(s.getMonth())} ${s.getFullYear()}`;
|
||||||
else if (data.range === 'year')
|
else if (data.range === 'year')
|
||||||
elPeriod.textContent = `Zeitraum: ${s.getFullYear()}`;
|
elPeriod.textContent = `Jahr: ${s.getFullYear()}`;
|
||||||
else
|
else
|
||||||
elPeriod.textContent = ''; // fallback: lieber leer als falsch
|
elPeriod.textContent = ''; // fallback: lieber leer als falsch
|
||||||
} else {
|
} else {
|
||||||
@@ -141,7 +139,7 @@ function render(data){
|
|||||||
|
|
||||||
// Keine Daten
|
// Keine Daten
|
||||||
if(data.hasData === false){
|
if(data.hasData === false){
|
||||||
elHint.innerHTML = `<b>Letzter Zeitpunkt</b> <span style="opacity:.7">(Keine Werte für diesen Zeitraum)</span>`;
|
elHint.innerHTML = `<b>${data.noDataHint || 'Keine Werte'}</b> <span style="opacity:.7">(Keine Werte für diesen Zeitraum)</span>`;
|
||||||
elGrid.innerHTML = '';
|
elGrid.innerHTML = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -162,7 +160,9 @@ function render(data){
|
|||||||
|
|
||||||
return `
|
return `
|
||||||
<div style="text-align:center;display:flex;flex-direction:column;align-items:center;gap:10px;">
|
<div style="text-align:center;display:flex;flex-direction:column;align-items:center;gap:10px;">
|
||||||
<div style="font-weight:900">${t}</div>
|
<div style="font-weight:800;margin-bottom:-6px;font-size:15px;">
|
||||||
|
${t}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="position:relative;width:160px;height:160px;">
|
<div style="position:relative;width:160px;height:160px;">
|
||||||
<svg width="160" height="160" viewBox="0 0 160 160">
|
<svg width="160" height="160" viewBox="0 0 160 160">
|
||||||
@@ -191,10 +191,9 @@ function render(data){
|
|||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const prod = v.Produktion || 0;
|
const prod = Number(v.Produktion) || 0;
|
||||||
const cons = v.Hausverbrauch || 0;
|
const cons = Number(v.Hausverbrauch) || 0;
|
||||||
const grid = v.Netz || 0;
|
const grid = Number(v.Netz) || 0;
|
||||||
const feed = v.Einspeisung || 0;
|
|
||||||
const eigen = Math.max(cons - grid, 0);
|
const eigen = Math.max(cons - grid, 0);
|
||||||
|
|
||||||
elGrid.innerHTML =
|
elGrid.innerHTML =
|
||||||
|
|||||||
+31
-21
@@ -35,7 +35,7 @@ class Energy_Pie extends IPSModule
|
|||||||
}
|
}
|
||||||
// Fullscreen-Fix: push periodically (adjust as you like)
|
// Fullscreen-Fix: push periodically (adjust as you like)
|
||||||
// 2000ms = alle 2 Sekunden (stabil, aber nicht ganz so brutal wie 1000ms)
|
// 2000ms = alle 2 Sekunden (stabil, aber nicht ganz so brutal wie 1000ms)
|
||||||
$this->SetTimerInterval('AutoPush', 2000);
|
$this->SetTimerInterval('AutoPush', 60000);
|
||||||
$this->RecalculateAndPush();
|
$this->RecalculateAndPush();
|
||||||
}
|
}
|
||||||
public function GetVisualizationTile(): string
|
public function GetVisualizationTile(): string
|
||||||
@@ -59,7 +59,7 @@ class Energy_Pie extends IPSModule
|
|||||||
break;
|
break;
|
||||||
case 'SetDate':
|
case 'SetDate':
|
||||||
$date = (string)$Value;
|
$date = (string)$Value;
|
||||||
if (!$this->isValidDate($date)) {
|
if (!$this->isValidDate($date) || strtotime($date . ' 00:00:00') > time()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->WriteAttributeString(self::ATTR_DATE, $date);
|
$this->WriteAttributeString(self::ATTR_DATE, $date);
|
||||||
@@ -90,8 +90,17 @@ class Energy_Pie extends IPSModule
|
|||||||
$prod = $this->readDelta($this->ReadPropertyInteger('VarProduction'), $tStart, $tEnd, $dbgProd);
|
$prod = $this->readDelta($this->ReadPropertyInteger('VarProduction'), $tStart, $tEnd, $dbgProd);
|
||||||
$feed = $this->readDelta($this->ReadPropertyInteger('VarFeedIn'), $tStart, $tEnd, $dbgFeed);
|
$feed = $this->readDelta($this->ReadPropertyInteger('VarFeedIn'), $tStart, $tEnd, $dbgFeed);
|
||||||
$grid = $this->readDelta($this->ReadPropertyInteger('VarGrid'), $tStart, $tEnd, $dbgGrid);
|
$grid = $this->readDelta($this->ReadPropertyInteger('VarGrid'), $tStart, $tEnd, $dbgGrid);
|
||||||
$hasData = (($dbgProd['count'] ?? 0) > 0) || (($dbgFeed['count'] ?? 0) > 0) || (($dbgGrid['count'] ?? 0) > 0);
|
$hasData = (($dbgProd['inRange'] ?? 0) > 0) || (($dbgFeed['inRange'] ?? 0) > 0) || (($dbgGrid['inRange'] ?? 0) > 0);
|
||||||
$noDataHint = (!$hasData && $range !== 'total') ? 'Letzter Zeitpunkt' : '';
|
$lastLogTs = 0;
|
||||||
|
if (!$hasData && $range !== 'total') {
|
||||||
|
$lastLogTs = max(
|
||||||
|
$this->getLastLogTimestamp($this->ReadPropertyInteger('VarProduction')),
|
||||||
|
$this->getLastLogTimestamp($this->ReadPropertyInteger('VarFeedIn')),
|
||||||
|
$this->getLastLogTimestamp($this->ReadPropertyInteger('VarGrid'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$noDataHint = ($lastLogTs > 0) ? 'Letzter Zeitpunkt: ' . date('d.m.Y H:i', $lastLogTs) : '';
|
||||||
|
|
||||||
|
|
||||||
// House = Prod - Feed + Grid
|
// House = Prod - Feed + Grid
|
||||||
@@ -109,13 +118,8 @@ class Energy_Pie extends IPSModule
|
|||||||
'Einspeisung' => (float)$feed,
|
'Einspeisung' => (float)$feed,
|
||||||
'Netz' => (float)$grid,
|
'Netz' => (float)$grid,
|
||||||
'Hausverbrauch' => (float)$house
|
'Hausverbrauch' => (float)$house
|
||||||
],
|
|
||||||
// kannst du später entfernen
|
|
||||||
'debug' => [
|
|
||||||
'prod' => $dbgProd,
|
|
||||||
'feed' => $dbgFeed,
|
|
||||||
'grid' => $dbgGrid
|
|
||||||
]
|
]
|
||||||
|
|
||||||
];
|
];
|
||||||
$this->UpdateVisualizationValue(json_encode($payload, JSON_THROW_ON_ERROR));
|
$this->UpdateVisualizationValue(json_encode($payload, JSON_THROW_ON_ERROR));
|
||||||
}
|
}
|
||||||
@@ -128,11 +132,13 @@ class Energy_Pie extends IPSModule
|
|||||||
$base = strtotime($dateYmd . ' 00:00:00') ?: strtotime(date('Y-m-d') . ' 00:00:00');
|
$base = strtotime($dateYmd . ' 00:00:00') ?: strtotime(date('Y-m-d') . ' 00:00:00');
|
||||||
switch ($range) {
|
switch ($range) {
|
||||||
case 'day':
|
case 'day':
|
||||||
return [$base, $base + 86400];
|
$end = strtotime('+1 day', $base);
|
||||||
|
return [$base, $end];
|
||||||
case 'week':
|
case 'week':
|
||||||
$dow = (int)date('N', $base); // 1=Mon..7=Sun
|
$dow = (int)date('N', $base); // 1=Mon..7=Sun
|
||||||
$start = $base - (($dow - 1) * 86400);
|
$start = strtotime('-' . ($dow - 1) . ' days', $base);
|
||||||
return [$start, $start + 7 * 86400];
|
$end = strtotime('+7 days', $start);
|
||||||
|
return [$start, $end];
|
||||||
case 'month':
|
case 'month':
|
||||||
$start = strtotime(date('Y-m-01 00:00:00', $base));
|
$start = strtotime(date('Y-m-01 00:00:00', $base));
|
||||||
$end = strtotime(date('Y-m-01 00:00:00', strtotime('+1 month', $start)));
|
$end = strtotime(date('Y-m-01 00:00:00', strtotime('+1 month', $start)));
|
||||||
@@ -144,7 +150,8 @@ class Energy_Pie extends IPSModule
|
|||||||
return [$start, $end];
|
return [$start, $end];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return [$base, $base + 86400];
|
$end = strtotime('+1 day', $base);
|
||||||
|
return [$base, $end];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function GetVisualizationPopup(): string
|
public function GetVisualizationPopup(): string
|
||||||
@@ -159,6 +166,7 @@ class Energy_Pie extends IPSModule
|
|||||||
'varId' => $varId,
|
'varId' => $varId,
|
||||||
'archiveId' => 0,
|
'archiveId' => 0,
|
||||||
'count' => 0,
|
'count' => 0,
|
||||||
|
'inRange' => 0,
|
||||||
'first' => null,
|
'first' => null,
|
||||||
'last' => null,
|
'last' => null,
|
||||||
'vStart' => null,
|
'vStart' => null,
|
||||||
@@ -172,18 +180,15 @@ class Energy_Pie extends IPSModule
|
|||||||
if ($archiveID <= 0) {
|
if ($archiveID <= 0) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
$values = @AC_GetLoggedValues($archiveID, $varId, $tStart - 86400, $tEnd + 86400, 0);
|
$values = @AC_GetLoggedValues($archiveID, $varId, max(0, $tStart - 86400), $tEnd, 0);
|
||||||
if (empty($values)) {
|
if (empty($values)) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
//usort($values, static fn($a, $b) => (int)$a['TimeStamp'] <=> (int)$b['TimeStamp']);
|
|
||||||
|
|
||||||
$firstTs = (int)$values[0]['TimeStamp'];
|
$firstTs = (int)$values[0]['TimeStamp'];
|
||||||
$lastTs = (int)$values[count($values) - 1]['TimeStamp'];
|
$lastTs = (int)$values[count($values) - 1]['TimeStamp'];
|
||||||
if ($firstTs > $lastTs) {
|
if ($firstTs > $lastTs) {
|
||||||
$values = array_reverse($values);
|
$values = array_reverse($values);
|
||||||
}
|
}
|
||||||
|
|
||||||
$dbg['count'] = count($values);
|
$dbg['count'] = count($values);
|
||||||
$dbg['first'] = (float)$values[0]['Value'];
|
$dbg['first'] = (float)$values[0]['Value'];
|
||||||
$dbg['last'] = (float)$values[count($values) - 1]['Value'];
|
$dbg['last'] = (float)$values[count($values) - 1]['Value'];
|
||||||
@@ -191,10 +196,16 @@ class Energy_Pie extends IPSModule
|
|||||||
$vEnd = null;
|
$vEnd = null;
|
||||||
foreach ($values as $v) {
|
foreach ($values as $v) {
|
||||||
$ts = (int)$v['TimeStamp'];
|
$ts = (int)$v['TimeStamp'];
|
||||||
|
if ($ts >= $tStart && $ts < $tEnd) {
|
||||||
|
$dbg['inRange']++;
|
||||||
|
}
|
||||||
if ($ts <= $tStart) $vStart = (float)$v['Value'];
|
if ($ts <= $tStart) $vStart = (float)$v['Value'];
|
||||||
if ($ts <= $tEnd) $vEnd = (float)$v['Value'];
|
if ($ts <= $tEnd) $vEnd = (float)$v['Value'];
|
||||||
if ($ts > $tEnd) break;
|
if ($ts > $tEnd) break;
|
||||||
}
|
}
|
||||||
|
if ($dbg['inRange'] === 0) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
if ($vStart === null) $vStart = $dbg['first'];
|
if ($vStart === null) $vStart = $dbg['first'];
|
||||||
if ($vEnd === null) $vEnd = $dbg['last'];
|
if ($vEnd === null) $vEnd = $dbg['last'];
|
||||||
$dbg['vStart'] = $vStart;
|
$dbg['vStart'] = $vStart;
|
||||||
@@ -202,7 +213,6 @@ class Energy_Pie extends IPSModule
|
|||||||
$diff = $vEnd - $vStart;
|
$diff = $vEnd - $vStart;
|
||||||
return ($diff < 0) ? 0.0 : (float)$diff;
|
return ($diff < 0) ? 0.0 : (float)$diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getLastLogTimestamp(int $varId): int
|
private function getLastLogTimestamp(int $varId): int
|
||||||
{
|
{
|
||||||
if ($varId <= 0 || !IPS_VariableExists($varId)) {
|
if ($varId <= 0 || !IPS_VariableExists($varId)) {
|
||||||
@@ -239,10 +249,10 @@ class Energy_Pie extends IPSModule
|
|||||||
$base = strtotime(($sign === -1 ? '-7 day' : '+7 day'), $base);
|
$base = strtotime(($sign === -1 ? '-7 day' : '+7 day'), $base);
|
||||||
break;
|
break;
|
||||||
case 'month':
|
case 'month':
|
||||||
$base = strtotime(($sign === -1 ? '-1 month' : '+1 month'), $base);
|
$base = strtotime(($sign === -1 ? 'first day of previous month' : 'first day of next month'), $base);
|
||||||
break;
|
break;
|
||||||
case 'year':
|
case 'year':
|
||||||
$base = strtotime(($sign === -1 ? '-1 year' : '+1 year'), $base);
|
$base = strtotime(($sign === -1 ? 'first day of january previous year' : 'first day of january next year'), $base);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$this->WriteAttributeString(self::ATTR_DATE, date('Y-m-d', $base));
|
$this->WriteAttributeString(self::ATTR_DATE, date('Y-m-d', $base));
|
||||||
|
|||||||
Reference in New Issue
Block a user