Energiemanager optimiert, Easee-Ladestation eingefügt.

This commit is contained in:
2025-08-07 08:45:19 +02:00
parent 6ffada6d29
commit aa150f58be
18 changed files with 1347 additions and 232 deletions

9
PV_Visu/form.json Normal file
View File

@@ -0,0 +1,9 @@
{
"elements": [
{ "type": "SelectVariable", "name": "VarProduction", "caption": "Produktion (kWh)" },
{ "type": "SelectVariable", "name": "VarConsumption", "caption": "Verbrauch (kWh)" },
{ "type": "SelectVariable", "name": "VarFeedIn", "caption": "Einspeisung (kWh)" },
{ "type": "SelectVariable", "name": "VarGrid", "caption": "Bezug Netz (kWh)" }
],
"actions": []
}

78
PV_Visu/module.html Normal file
View File

@@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
html, body { margin: 0; padding: 8px; background: transparent; font-family: sans-serif; color: #ffffff; }
.bar-block { margin-bottom: 20px; }
.bar-title { font-size: 1.2em; font-weight: bold; margin-bottom: 6px; }
.bar-container { width: 100%; background: #ddd; border-radius: 4px; overflow: hidden; height: 24px; position: relative; }
.bar { height: 100%; float: left; position: relative; }
.bar span { position: absolute; width: 100%; text-align: center; line-height: 24px; font-size: 0.8em; color: #fff; }
.bar-cons { background: #4CAF50; }
.bar-feed { background: #8BC34A; }
.bar-pv { background: #FF9800; }
.bar-grid { background: #FF5722; }
.value-text { font-size: 0.95em; margin-top: 4px; }
</style>
</head>
<body>
<div id="pv_visu">
<div class="bar-block">
<div class="bar-title">Produktion (Eigenverbrauch / Einspeisung)</div>
<div class="bar-container">
<div class="bar bar-cons" id="barCons"><span id="barConsText"></span></div>
<div class="bar bar-feed" id="barFeed"><span id="barFeedText"></span></div>
</div>
<div class="value-text" id="prodValues"></div>
</div>
<div class="bar-block">
<div class="bar-title">Verbrauch (PV / Netz)</div>
<div class="bar-container">
<div class="bar bar-pv" id="barPV"><span id="barPVText"></span></div>
<div class="bar bar-grid" id="barGrid"><span id="barGridText"></span></div>
</div>
<div class="value-text" id="consValues"></div>
</div>
</div>
<script>
function Apply(data) {
document.getElementById('barCons').style.width = data.prodCons + '%';
document.getElementById('barFeed').style.width = data.prodFeed + '%';
document.getElementById('barPV').style.width = data.consPV + '%';
document.getElementById('barGrid').style.width = data.consGrid + '%';
document.getElementById('barConsText').innerText = data.prodCons + '%';
document.getElementById('barFeedText').innerText = data.prodFeed + '%';
document.getElementById('barPVText').innerText = data.consPV + '%';
document.getElementById('barGridText').innerText = data.consGrid + '%';
document.getElementById('prodValues').innerText =
'Gesamt: ' + data.value.prod + ' kWh, Eigenverbrauch: ' + (data.consPV/100*data.value.cons).toFixed(2) + ' kWh, Einspeisung: ' + data.value.feed + ' kWh';
document.getElementById('consValues').innerText =
'Gesamt: ' + data.value.cons + ' kWh, PV-Anteil: ' + (data.consPV/100*data.value.cons).toFixed(2) + ' kWh, Netz: ' + data.value.grid + ' kWh';
}
function handleMessage(msg) {
try {
const data = typeof msg === 'string' ? JSON.parse(msg) : msg;
Apply(data);
} catch (e) {
console.error('Fehler beim Verarbeiten der Daten:', e, msg);
}
}
if (typeof registerMessageHandler === 'function') {
registerMessageHandler(handleMessage);
}
// Live-Aktualisierung alle 30 Sekunden
function pollData() {
if (typeof IPS !== 'undefined') {
IPS.RequestAction('update', '');
}
}
setInterval(pollData, 30000);
</script>
</body>
</html>

12
PV_Visu/module.json Normal file
View File

@@ -0,0 +1,12 @@
{
"id": "{DDE89CBE-4411-5FF4-4931-14204E05CAD0}",
"name": "PV_Visu",
"type": 3,
"vendor": "Belevo AG",
"aliases": [],
"parentRequirements": [],
"childRequirements": [],
"implemented": [],
"prefix": "",
"url": ""
}

99
PV_Visu/module.php Normal file
View File

@@ -0,0 +1,99 @@
<?php
class PV_Visu extends IPSModule
{
public function Create()
{
parent::Create();
$this->RegisterPropertyInteger('VarProduction', 0);
$this->RegisterPropertyInteger('VarConsumption', 0);
$this->RegisterPropertyInteger('VarFeedIn', 0);
$this->RegisterPropertyInteger('VarGrid', 0);
$this->RegisterVariableString('JSONData', 'Visualisierungsdaten', '', 0);
IPS_SetHidden($this->GetIDForIdent('JSONData'), true);
$this->SetVisualizationType(1); // HTML SDK Tile
}
public function ApplyChanges()
{
parent::ApplyChanges();
foreach (['VarProduction', 'VarConsumption', 'VarFeedIn', 'VarGrid'] as $prop) {
$vid = $this->ReadPropertyInteger($prop);
if ($vid > 0) {
$this->RegisterMessage($vid, VM_UPDATE);
}
}
$this->UpdateData(); // Initial
}
public function MessageSink($TimeStamp, $SenderID, $Message, $Data)
{
if ($Message === VM_UPDATE) {
$this->UpdateData();
}
}
public function GetVisualizationTile()
{
$initialData = '<script>handleMessage(' . json_encode($this->UpdateData()) . ');</script>';
$html = file_get_contents(__DIR__ . '/module.html');
return $html . $initialData;
}
public function RequestAction($Ident, $Value)
{
if ($Ident === 'update') {
return $this->UpdateData(); // Rückgabe für Visualisierung
}
throw new \Exception("Unknown Ident: $Ident");
}
public function UpdateData()
{
$start = strtotime('today 00:00');
$end = time();
$prod = $this->GetDailyTotal($this->ReadPropertyInteger('VarProduction'), $start, $end);
$cons = $this->GetDailyTotal($this->ReadPropertyInteger('VarConsumption'), $start, $end);
$feed = $this->GetDailyTotal($this->ReadPropertyInteger('VarFeedIn'), $start, $end);
$grid = $this->GetDailyTotal($this->ReadPropertyInteger('VarGrid'), $start, $end);
$prodCons = $prod > 0 ? (($cons - $grid) / $prod) * 100 : 0;
$prodFeed = $prod > 0 ? 100 - $prodCons : 0;
$consPV = $cons > 0 ? min($prod, ($cons - $grid)) / $cons * 100 : 0;
$consGrid = $cons > 0 ? 100 - $consPV : 0;
$data = [
'prodCons' => round($prodCons, 1),
'prodFeed' => round($prodFeed, 1),
'consPV' => round($consPV, 1),
'consGrid' => round($consGrid, 1),
'value' => [
'prod' => round($prod, 2),
'cons' => round($cons, 2),
'feed' => round($feed, 2),
'grid' => round($grid, 2),
],
];
$json = json_encode($data);
SetValueString($this->GetIDForIdent('JSONData'), $json);
return $data;
}
private function GetDailyTotal(int $varID, int $start, int $end)
{
if ($varID <= 0) return 0.0;
$archiveID = @IPS_GetInstanceListByModuleID('{43192F0B-135B-4CE7-A0A7-1475603F3060}')[0];
if (!$archiveID) return 0.0;
$values = @AC_GetAggregatedValues($archiveID, $varID, 1, $start, $end, 1);
return isset($values[0]['Avg']) ? (float)$values[0]['Avg'] : 0.0;
}
}

59
PV_Visu/readme.md Normal file
View File

@@ -0,0 +1,59 @@
# PV_Visu
Visualisierung des Eigenverbrauchs: Tages-Quoten für PV-Produktion vs. Einspeisung und Verbrauch vs. Netz-Bezug.
## Inhaltsverzeichnis
1. [Funktionsumfang](#funktionsumfang)
2. [Voraussetzungen](#voraussetzungen)
3. [Installation](#installation)
4. [Instanz einrichten](#instanz-einrichten)
5. [WebFront](#webfront)
6. [PHP-Befehlsreferenz](#php-befehlsreferenz)
## Funktionsumfang
- Anzeige von Tages-Quoten (%)
- Produktion: Eigenverbrauch vs. Einspeisung
- Verbrauch: PV-Anteil vs. Netz-Anteil
- Zwei Balkendiagramme
- Absolute Tages-Summen (kWh)
## Voraussetzungen
- IP-Symcon ≥ 7.1
- Archiv-Modul aktiviert
- Vier kWh-Zähler-Variablen
## Installation
1. **Module Store** → Suche nach „PV_Visu“ und installieren
2. **Alternativ**: Unter Module → Repositories folgende URL hinzufügen:
```
https://github.com/DeinRepo/PV_Visu.git
```
und Modul neu einlesen.
## Instanz einrichten
- **Instanz hinzufügen** → Filter: „PV_Visu“
- Variablen zuweisen:
| Property | Beschreibung |
| -------------- | -------------------------- |
| VarProduction | PV-Produktionszähler (kWh) |
| VarConsumption | Gesamtverbrauch (kWh) |
| VarFeedIn | Einspeisung (kWh) |
| VarGrid | Netz-Bezug (kWh) |
## WebFront
- **Tile-Typ:** PV_Visu
- Balken 1 (Grün): Produktion
- Balken 2 (Orange/Rot): Verbrauch
## PHP-Befehlsreferenz
```php
IPS_RequestAction($InstanceID, 'update', true);
```