diff --git a/Abrechnung/form.json b/Abrechnung/form.json
index c38b831..92235cb 100644
--- a/Abrechnung/form.json
+++ b/Abrechnung/form.json
@@ -19,121 +19,116 @@
"name": "FooterText",
"caption": "Fusszeile"
},
-
{
-
- "type": "List",
- "name": "Users",
- "caption": "Benutzerliste",
- "add": true,
- "delete": true,
- "sortable": true,
- "columns": [
- { "caption": "ID", "name": "id", "width": "10%", "add": "", "edit": { "type": "ValidationTextBox" } },
- { "caption": "Name", "name": "name", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } },
- { "caption": "Adresse", "name": "address", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } },
- { "caption": "Ort", "name": "city", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } }
- ]
-
+ "type": "Label",
+ "caption": "🏦 QR-Einzahlungsschein Daten"
},
-
{
-
- "type": "List",
- "name": "PowerMeters",
- "caption": "Stromzählerliste",
- "add": true,
- "delete": true,
- "sortable": true,
- "columns": [
- { "caption": "ID", "name": "id", "width": "10%", "add": "", "edit": { "type": "ValidationTextBox" } },
- { "caption": "Name", "name": "name", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } },
- { "caption": "Var. Verbrauch", "name": "var_consumption", "width": "20%", "add": 0, "edit": { "type": "SelectVariable" } },
- { "caption": "Var. Rückspeisung", "name": "var_feed", "width": "20%", "add": 0, "edit": { "type": "SelectVariable" } },
- { "caption": "Benutzer-ID", "name": "user_id", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } }
- ]
+ "type": "ValidationTextBox",
+ "name": "CreditorName",
+ "caption": "Rechnungssteller Name"
},
-
{
-
- "type": "List",
- "name": "WaterMeters",
- "caption": "Verbrauchszählerliste",
- "add": true,
- "delete": true,
- "sortable": true,
- "columns": [
- { "caption": "ID", "name": "id", "width": "10%", "add": "", "edit": { "type": "ValidationTextBox" } },
- { "caption": "Name", "name": "name", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } },
- { "caption": "Var. Verbrauch", "name": "var_consumption", "width": "20%", "add": 0, "edit": { "type": "SelectVariable" } },
- { "caption": "Benutzer-ID", "name": "user_id", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } },
- {
- "caption": "Zählertyp",
- "name": "meter_type",
- "width": "20%",
- "add": "Warmwasser",
- "edit": {
- "type": "Select",
- "options": [
- { "caption": "Warmwasser", "value": "Warmwasser" },
- { "caption": "Kaltwasser", "value": "Kaltwasser" },
- { "caption": "Wärme", "value": "Wärme" }
- ]
- }
- }
-
+ "type": "ValidationTextBox",
+ "name": "CreditorAddress",
+ "caption": "Rechnungssteller Strasse/Nr."
+ },
+ {
+ "type": "ValidationTextBox",
+ "name": "CreditorCity",
+ "caption": "Rechnungssteller PLZ/Ort"
+ },
+ {
+ "type": "ValidationTextBox",
+ "name": "BankIBAN",
+ "caption": "Bank IBAN"
+ },
+ {
+ "type": "List",
+ "name": "Users",
+ "caption": "Benutzerliste",
+ "add": true,
+ "delete": true,
+ "sortable": true,
+ "columns": [
+ { "caption": "ID", "name": "id", "width": "10%", "add": "", "edit": { "type": "ValidationTextBox" } },
+ { "caption": "Name", "name": "name", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } },
+ { "caption": "Adresse", "name": "address", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } },
+ { "caption": "Ort", "name": "city", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } }
]
},
-
{
-
- "type": "List",
- "name": "Tariffs",
- "caption": "Tarifübersicht",
- "add": true,
- "delete": true,
- "sortable": true,
- "columns": [
- {
- "caption": "Startdatum",
- "name": "start",
- "width": "20%",
- "add": "",
- "edit": { "type": "SelectDate" }
- },
- {
- "caption": "Enddatum",
- "name": "end",
- "width": "20%",
- "add": "",
- "edit": { "type": "SelectDate" }
- },
- {
- "caption": "Tarif (Rp/Einheit)",
- "name": "price",
- "width": "20%",
- "add": 0,
- "edit": { "type": "NumberSpinner", "digits": 3, "minimum": 0 }
- },
- {
- "caption": "Einheit",
- "name": "unit_type",
- "width": "20%",
- "add": "Netztarif",
- "edit": {
- "type": "Select",
- "options": [
- { "caption": "Netztarif", "value": "Netztarif" },
- { "caption": "Einspeisetarif", "value": "Einspeisetarif" },
- { "caption": "Solartarif", "value": "Solartarif" },
- { "caption": "Warmwasser", "value": "Warmwasser" },
- { "caption": "Kaltwasser", "value": "Kaltwasser" },
- { "caption": "Wärme", "value": "Wärme" }
- ]
- }
- }
- ]
+ "type": "List",
+ "name": "PowerMeters",
+ "caption": "Stromzählerliste",
+ "add": true,
+ "delete": true,
+ "sortable": true,
+ "columns": [
+ { "caption": "ID", "name": "id", "width": "10%", "add": "", "edit": { "type": "ValidationTextBox" } },
+ { "caption": "Name", "name": "name", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } },
+ { "caption": "Var. Verbrauch", "name": "var_consumption", "width": "20%", "add": 0, "edit": { "type": "SelectVariable" } },
+ { "caption": "Var. Rückspeisung", "name": "var_feed", "width": "20%", "add": 0, "edit": { "type": "SelectVariable" } },
+ { "caption": "Benutzer-ID", "name": "user_id", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } }
+ ]
+ },
+ {
+ "type": "List",
+ "name": "WaterMeters",
+ "caption": "Verbrauchszählerliste",
+ "add": true,
+ "delete": true,
+ "sortable": true,
+ "columns": [
+ { "caption": "ID", "name": "id", "width": "10%", "add": "", "edit": { "type": "ValidationTextBox" } },
+ { "caption": "Name", "name": "name", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } },
+ { "caption": "Var. Verbrauch", "name": "var_consumption", "width": "20%", "add": 0, "edit": { "type": "SelectVariable" } },
+ { "caption": "Benutzer-ID", "name": "user_id", "width": "20%", "add": "", "edit": { "type": "ValidationTextBox" } },
+ {
+ "caption": "Zählertyp",
+ "name": "meter_type",
+ "width": "20%",
+ "add": "Warmwasser",
+ "edit": {
+ "type": "Select",
+ "options": [
+ { "caption": "Warmwasser", "value": "Warmwasser" },
+ { "caption": "Kaltwasser", "value": "Kaltwasser" },
+ { "caption": "Wärme", "value": "Wärme" }
+ ]
+ }
}
-
+ ]
+ },
+ {
+ "type": "List",
+ "name": "Tariffs",
+ "caption": "Tarifübersicht",
+ "add": true,
+ "delete": true,
+ "sortable": true,
+ "columns": [
+ { "caption": "Startdatum", "name": "start", "width": "20%", "add": "", "edit": { "type": "SelectDate" } },
+ { "caption": "Enddatum", "name": "end", "width": "20%", "add": "", "edit": { "type": "SelectDate" } },
+ { "caption": "Tarif (Rp/Einheit)", "name": "price", "width": "20%", "add": 0, "edit": { "type": "NumberSpinner", "digits": 3, "minimum": 0 } },
+ {
+ "caption": "Einheit",
+ "name": "unit_type",
+ "width": "20%",
+ "add": "Netztarif",
+ "edit": {
+ "type": "Select",
+ "options": [
+ { "caption": "Netztarif", "value": "Netztarif" },
+ { "caption": "Einspeisetarif", "value": "Einspeisetarif" },
+ { "caption": "Solartarif", "value": "Solartarif" },
+ { "caption": "Warmwasser", "value": "Warmwasser" },
+ { "caption": "Kaltwasser", "value": "Kaltwasser" },
+ { "caption": "Wärme", "value": "Wärme" }
+ ]
+ }
+ }
+ ]
+ }
]
-}
+}
\ No newline at end of file
diff --git a/Abrechnung/module.php b/Abrechnung/module.php
index d61faf1..447f250 100644
--- a/Abrechnung/module.php
+++ b/Abrechnung/module.php
@@ -44,6 +44,12 @@ class Abrechnung extends IPSModule
$this->RegisterPropertyString('PropertyText', 'Liegenschaft');
$this->RegisterPropertyString('FooterText', 'Belevo AG • 6122 Menznau • www.belevo.ch');
+ // Neue Felder für den QR-Schein
+ $this->RegisterPropertyString('CreditorName', 'Belevo AG');
+ $this->RegisterPropertyString('CreditorAddress', 'Musterstrasse 1');
+ $this->RegisterPropertyString('CreditorCity', '6122 Menznau');
+ $this->RegisterPropertyString('BankIBAN', '');
+
$this->RegisterVariableInteger('FromDate', 'Startdatum', '~UnixTimestamp', 1);
$this->RegisterVariableInteger('ToDate', 'Enddatum', '~UnixTimestamp', 2);
$this->RegisterVariableString('LastResult', 'Letzte Abrechnung', '', 3);
@@ -139,7 +145,11 @@ class Abrechnung extends IPSModule
foreach ($users as $user) {
$pdf->AddPage();
- $this->BuildUserInvoice($pdf, $user, $power, $water, $tariffs, $from, $to);
+ // Hole das berechnete Total aus der Rechnung
+ $grandTotal = $this->BuildUserInvoice($pdf, $user, $power, $water, $tariffs, $from, $to);
+
+ // Generiere den Einzahlungsschein, wenn eine IBAN vorhanden ist
+ $this->BuildQRBill($pdf, $user, $grandTotal);
}
return $pdf->Output('Abrechnung.pdf', 'S');
@@ -223,6 +233,136 @@ class Abrechnung extends IPSModule
";
$pdf->writeHTML($html, true, false, true, false, '');
+
+ // WICHTIG: Total zurückgeben für den Einzahlungsschein
+ return $grandTotal;
+ }
+
+ // ====================== QR-Einzahlungsschein (Schweiz) ======================
+
+ private function BuildQRBill($pdf, $user, $amount)
+ {
+ $iban = str_replace(' ', '', $this->ReadPropertyString('BankIBAN'));
+
+ // Kein Einzahlungsschein, wenn IBAN leer ist oder Betrag <= 0
+ if (empty($iban) || $amount <= 0) {
+ return;
+ }
+
+ $pdf->AddPage();
+ $pdf->SetAutoPageBreak(false);
+
+ // Position des Einzahlungsscheins unten auf A4 (Höhe 105mm)
+ $yStart = 192;
+
+ // Trennlinien zeichnen
+ $pdf->SetLineStyle(['dash' => '2,2', 'color' => [0, 0, 0]]);
+ $pdf->Line(0, $yStart, 210, $yStart); // Horizontal
+ $pdf->Line(62, $yStart, 62, 297); // Vertikal
+ $pdf->SetLineStyle(['dash' => 0, 'color' => [0, 0, 0]]); // Reset
+
+ $creditorName = $this->ReadPropertyString('CreditorName');
+ $creditorCity = $this->ReadPropertyString('CreditorCity');
+ $bankIBAN_formatted = wordwrap($iban, 4, ' ', true);
+
+ // --- LINKER TEIL: Empfangsschein ---
+ $pdf->SetFont('dejavusans', 'B', 11);
+ $pdf->SetXY(5, $yStart + 5);
+ $pdf->Cell(52, 5, 'Empfangsschein', 0, 1);
+
+ $pdf->SetFont('dejavusans', 'B', 6);
+ $pdf->SetXY(5, $yStart + 12);
+ $pdf->Cell(52, 3, 'Konto / Zahlbar an', 0, 1);
+ $pdf->SetFont('dejavusans', '', 6);
+ $pdf->SetX(5); $pdf->Cell(52, 3, $bankIBAN_formatted, 0, 1);
+ $pdf->SetX(5); $pdf->Cell(52, 3, $creditorName, 0, 1);
+ $pdf->SetX(5); $pdf->Cell(52, 3, $creditorCity, 0, 1);
+
+ $pdf->SetFont('dejavusans', 'B', 6);
+ $pdf->SetXY(5, $yStart + 35);
+ $pdf->Cell(52, 3, 'Zahlbar durch', 0, 1);
+ $pdf->SetFont('dejavusans', '', 6);
+ $pdf->SetX(5); $pdf->Cell(52, 3, $user['name'] ?? '', 0, 1);
+ $pdf->SetX(5); $pdf->Cell(52, 3, $user['address'] ?? '', 0, 1);
+ $pdf->SetX(5); $pdf->Cell(52, 3, $user['city'] ?? '', 0, 1);
+
+ $pdf->SetFont('dejavusans', 'B', 6);
+ $pdf->SetXY(5, $yStart + 60);
+ $pdf->Cell(15, 3, 'Währung', 0, 0);
+ $pdf->Cell(20, 3, 'Betrag', 0, 1);
+ $pdf->SetFont('dejavusans', '', 8);
+ $pdf->SetX(5);
+ $pdf->Cell(15, 4, 'CHF', 0, 0);
+ $pdf->Cell(20, 4, number_format($amount, 2, '.', ''), 0, 1);
+
+ // --- RECHTER TEIL: Zahlteil ---
+ $pdf->SetFont('dejavusans', 'B', 11);
+ $pdf->SetXY(118, $yStart + 5);
+ $pdf->Cell(50, 5, 'Zahlteil', 0, 1);
+
+ // QR Code String generieren & rendern (46x46mm)
+ $qrString = $this->GenerateQRString($iban, $amount, $user);
+ $style = ['border' => false, 'padding' => 0, 'fgcolor' => [0, 0, 0], 'bgcolor' => false];
+ $pdf->write2DBarcode($qrString, 'QRCODE,M', 67, $yStart + 17, 46, 46, $style, 'N');
+
+ // Schweizer Kreuz über den QR Code zeichnen (7x7mm Block)
+ $pdf->SetFillColor(0, 0, 0);
+ $pdf->Rect(67 + 19.5, $yStart + 17 + 19.5, 7, 7, 'F');
+ $pdf->SetFillColor(255, 255, 255);
+ $pdf->Rect(67 + 19.5 + 3, $yStart + 17 + 19.5 + 1, 1, 5, 'F');
+ $pdf->Rect(67 + 19.5 + 1, $yStart + 17 + 19.5 + 3, 5, 1, 'F');
+
+ $pdf->SetFont('dejavusans', 'B', 8);
+ $pdf->SetXY(118, $yStart + 17);
+ $pdf->Cell(80, 4, 'Konto / Zahlbar an', 0, 1);
+ $pdf->SetFont('dejavusans', '', 8);
+ $pdf->SetX(118); $pdf->Cell(80, 4, $bankIBAN_formatted, 0, 1);
+ $pdf->SetX(118); $pdf->Cell(80, 4, $creditorName, 0, 1);
+ $pdf->SetX(118); $pdf->Cell(80, 4, $creditorCity, 0, 1);
+
+ $pdf->SetFont('dejavusans', 'B', 8);
+ $pdf->SetXY(118, $yStart + 40);
+ $pdf->Cell(80, 4, 'Zahlbar durch', 0, 1);
+ $pdf->SetFont('dejavusans', '', 8);
+ $pdf->SetX(118); $pdf->Cell(80, 4, $user['name'] ?? '', 0, 1);
+ $pdf->SetX(118); $pdf->Cell(80, 4, $user['address'] ?? '', 0, 1);
+ $pdf->SetX(118); $pdf->Cell(80, 4, $user['city'] ?? '', 0, 1);
+
+ $pdf->SetFont('dejavusans', 'B', 8);
+ $pdf->SetXY(67, $yStart + 68);
+ $pdf->Cell(15, 4, 'Währung', 0, 0);
+ $pdf->Cell(20, 4, 'Betrag', 0, 1);
+ $pdf->SetFont('dejavusans', '', 10);
+ $pdf->SetX(67);
+ $pdf->Cell(15, 5, 'CHF', 0, 0);
+ $pdf->Cell(20, 5, number_format($amount, 2, '.', ''), 0, 1);
+ }
+
+ private function GenerateQRString($iban, $amount, $user)
+ {
+ // Daten nach SIX Swiss Payment Standard beschneiden (max 70 Zeichen pro Zeile)
+ $creditorName = mb_substr($this->ReadPropertyString('CreditorName'), 0, 70);
+ $creditorStr = mb_substr($this->ReadPropertyString('CreditorAddress'), 0, 70);
+ $creditorCity = mb_substr($this->ReadPropertyString('CreditorCity'), 0, 70);
+
+ $debtorName = mb_substr($user['name'] ?? '', 0, 70);
+ $debtorStr = mb_substr($user['address'] ?? '', 0, 70);
+ $debtorCity = mb_substr($user['city'] ?? '', 0, 70);
+
+ $amountStr = number_format($amount, 2, '.', '');
+
+ // EPC / Swiss QR Code String Format
+ $lines = [
+ 'SPC', '0200', '1', $iban, 'K',
+ $creditorName, $creditorStr, $creditorCity, '', '', 'CH',
+ '', '', '', '', '', '', '', // Ultimate Creditor (leer)
+ $amountStr, 'CHF', 'K',
+ $debtorName, $debtorStr, $debtorCity, '', '', 'CH',
+ 'NON', '', // Reference Type (NON = Ohne Referenz)
+ 'EPD', 'Abrechnung Liegenschaft'
+ ];
+
+ return implode("\r\n", $lines);
}
// ====================== Stromkosten (15-Minuten, alle User) ======================
@@ -396,121 +536,121 @@ class Abrechnung extends IPSModule
}
}
-private function GetCalculatedPowerCosts($userId)
-{
- $html = "
-
+ /* Neue Formatierungen */
+ .num {
+ text-align: right;
+ font-family: monospace;
+ width: 90px;
+ }
+ .subtotal-row {
+ border-top: 1px solid black;
+ font-weight: bold;
+ }
+ .total-row {
+ border-top: 3px double black;
+ font-weight: bold;
+ background-color: #ddd;
+ }
+
-
-
- | ID |
- Import (kWh) |
- Export (kWh) |
- ZEV-Haus (kWh) |
- Netz-Haus (kWh) |
- Solar-Netz (kWh) |
- Solar-ZEV (kWh) |
- Kauf Solar (CHF) |
- Kauf Netz (CHF) |
- Verkauf Netz(CHF) |
- Verkauf ZEV(CHF) |
- Total CHF |
-
";
+
+
+ | ID |
+ Import (kWh) |
+ Export (kWh) |
+ ZEV-Haus (kWh) |
+ Netz-Haus (kWh) |
+ Solar-Netz (kWh) |
+ Solar-ZEV (kWh) |
+ Kauf Solar (CHF) |
+ Kauf Netz (CHF) |
+ Verkauf Netz(CHF) |
+ Verkauf ZEV(CHF) |
+ Total CHF |
+
";
- if (empty($this->powerCostCache) || !isset($this->powerCostCache[$userId])) {
- $html .= "| Keine Stromzähler für diesen Benutzer |
";
- return ['html' => $html, 'sum' => 0.0];
+ if (empty($this->powerCostCache) || !isset($this->powerCostCache[$userId])) {
+ $html .= "| Keine Stromzähler für diesen Benutzer |
";
+ return ['html' => $html, 'sum' => 0.0];
+ }
+
+ $sum = 0.0;
+ $rowIndex = 0;
+
+ foreach ($this->powerCostCache[$userId] as $name => $a) {
+
+ $subtotal = $a['cost_grid'] + $a['cost_solar'] - ($a['rev_feedin'] + $a['rev_zev']);
+ $sum += $subtotal;
+
+ $rowClass = ($rowIndex % 2 === 0) ? "row-even" : "row-odd";
+ $rowIndex++;
+
+ // Datenzeile
+ $html .= "
+ | {$a['name']} |
+ " . number_format($a['imp'], 3, '.', "'") . " |
+ " . number_format($a['exp'], 3, '.', "'") . " |
+ " . number_format($a['solar_bezug'], 3, '.', "'") . " |
+ " . number_format($a['netz_bezug'], 3, '.', "'") . " |
+ " . number_format($a['solareinspeisung'], 3, '.', "'") . " |
+ " . number_format($a['solarverkauf'], 3, '.', "'") . " |
+ " . number_format($a['cost_solar'], 2, '.', "'") . " |
+ " . number_format($a['cost_grid'], 2, '.', "'") . " |
+ " . number_format($a['rev_feedin'], 2, '.', "'") . " |
+ " . number_format($a['rev_zev'], 2, '.', "'") . " |
+ " . number_format($subtotal, 2, '.', "'") . " |
+
";
+
+ // Leerzeile
+ $html .= " |
";
+ }
+
+ // Gesamttotal
+ $html .= "
+
+ | Total |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ " . number_format($sum, 2, '.', "'") . " |
+
+ ";
+
+ return ['html' => $html, 'sum' => $sum];
}
- $sum = 0.0;
- $rowIndex = 0;
-
- foreach ($this->powerCostCache[$userId] as $name => $a) {
-
- $subtotal = $a['cost_grid'] + $a['cost_solar'] - ($a['rev_feedin'] + $a['rev_zev']);
- $sum += $subtotal;
-
- $rowClass = ($rowIndex % 2 === 0) ? "row-even" : "row-odd";
- $rowIndex++;
-
- // Datenzeile
- $html .= "
- | {$a['name']} |
- " . number_format($a['imp'], 3, '.', "'") . " |
- " . number_format($a['exp'], 3, '.', "'") . " |
- " . number_format($a['solar_bezug'], 3, '.', "'") . " |
- " . number_format($a['netz_bezug'], 3, '.', "'") . " |
- " . number_format($a['solareinspeisung'], 3, '.', "'") . " |
- " . number_format($a['solarverkauf'], 3, '.', "'") . " |
- " . number_format($a['cost_solar'], 2, '.', "'") . " |
- " . number_format($a['cost_grid'], 2, '.', "'") . " |
- " . number_format($a['rev_feedin'], 2, '.', "'") . " |
- " . number_format($a['rev_zev'], 2, '.', "'") . " |
- " . number_format($subtotal, 2, '.', "'") . " |
-
";
-
- // Leerzeile
- $html .= " |
";
- }
-
- // Gesamttotal
- $html .= "
-
- | Total |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- " . number_format($sum, 2, '.', "'") . " |
-
- ";
-
- return ['html' => $html, 'sum' => $sum];
-}
-
// ====================== Nebenkosten Wasser/Wärme ======================
private function CalculateAdditionalCosts($waterMeters, $tariffs, $userId, $from, $to)
@@ -638,62 +778,61 @@ private function GetCalculatedPowerCosts($userId)
// ====================== Hilfsfunktionen ======================
-private function GetValueAt($varId, $timestamp, $nearestAfter = true)
-{
- $archiveID = @IPS_GetInstanceListByModuleID('{43192F0B-135B-4CE7-A0A7-1475603F3060}')[0];
- if (!$archiveID || !IPS_VariableExists($varId)) {
- return null;
+ private function GetValueAt($varId, $timestamp, $nearestAfter = true)
+ {
+ $archiveID = @IPS_GetInstanceListByModuleID('{43192F0B-135B-4CE7-A0A7-1475603F3060}')[0];
+ if (!$archiveID || !IPS_VariableExists($varId)) {
+ return null;
+ }
+
+ if ($nearestAfter) {
+ // Erster Wert NACH oder GENAU ab Timestamp
+ $values = @AC_GetLoggedValues(
+ $archiveID,
+ $varId,
+ $timestamp, // start
+ time(), // end
+ 1 // LIMIT
+ );
+ } else {
+ // Letzter Wert DAVOR oder GENAU bis Timestamp
+ $values = @AC_GetLoggedValues(
+ $archiveID,
+ $varId,
+ 0, // start
+ $timestamp, // end
+ 1 // LIMIT
+ );
+ }
+
+ if (!empty($values)) {
+ return (float)$values[0]['Value'];
+ }
+
+ // Fallback → Live-Wert
+ return (float)GetValue($varId);
}
- if ($nearestAfter) {
- // Erster Wert NACH oder GENAU ab Timestamp
- $values = @AC_GetLoggedValues(
- $archiveID,
- $varId,
- $timestamp, // start
- time(), // end
- 1 // LIMIT
- );
- } else {
- // Letzter Wert DAVOR oder GENAU bis Timestamp
- $values = @AC_GetLoggedValues(
- $archiveID,
- $varId,
- 0, // start
- $timestamp, // end
- 1 // LIMIT
- );
+ private function getDeltaFromArchive(int $varId, int $tStart, int $tEnd): float
+ {
+ // Werte holen
+ $startValue = $this->GetValueAt($varId, $tStart, false);
+ $endValue = $this->GetValueAt($varId, $tEnd, false);
+
+ if ($startValue === null || $endValue === null) {
+ return 0.0;
+ }
+
+ // Delta berechnen
+ $diff = $endValue - $startValue;
+
+ if ($diff < 0) {
+ $diff = 0.0;
+ }
+
+ return (float)$diff;
}
- if (!empty($values)) {
- return (float)$values[0]['Value'];
- }
-
- // Fallback → Live-Wert
- return (float)GetValue($varId);
-}
-
-
-private function getDeltaFromArchive(int $varId, int $tStart, int $tEnd): float
-{
- // Werte holen
- $startValue = $this->GetValueAt($varId, $tStart, false);
- $endValue = $this->GetValueAt($varId, $tEnd, false);
-
- if ($startValue === null || $endValue === null) {
- return 0.0;
- }
-
- // Delta berechnen
- $diff = $endValue - $startValue;
-
- if ($diff < 0) {
- $diff = 0.0;
- }
-
- return (float)$diff;
-}
-
private function toUnixTs($val, $endOfDay = false)
{
if (is_int($val)) {
@@ -724,52 +863,6 @@ private function getDeltaFromArchive(int $varId, int $tStart, int $tEnd): float
return null;
}
- private function readDelta($varId, $tStart, $tEnd)
- {
- if (!is_int($tStart)) {
- $tStart = strtotime($tStart);
- }
- if (!is_int($tEnd)) {
- $tEnd = strtotime($tEnd);
- }
-
- $archiveID = @IPS_GetInstanceListByModuleID('{43192F0B-135B-4CE7-A0A7-1475603F3060}')[0];
- if (!$archiveID || !IPS_VariableExists($varId)) {
- return 0.0;
- }
-
- $values = @AC_GetLoggedValues($archiveID, $varId, $tStart - 86400, $tEnd + 86400, 0);
- if (empty($values)) {
- return 0.0;
- }
-
- usort($values, fn($a, $b) => (int)$a['TimeStamp'] <=> (int)$b['TimeStamp']);
- $vStart = null;
- $vEnd = null;
-
- foreach ($values as $v) {
- if ($v['TimeStamp'] <= $tStart) {
- $vStart = $v['Value'];
- }
- if ($v['TimeStamp'] <= $tEnd) {
- $vEnd = $v['Value'];
- }
- if ($v['TimeStamp'] > $tEnd) {
- break;
- }
- }
-
- if ($vStart === null) {
- $vStart = (float)GetValue($varId);
- }
- if ($vEnd === null) {
- $vEnd = (float)GetValue($varId);
- }
-
- $diff = $vEnd - $vStart;
- return ($diff < 0) ? 0.0 : $diff;
- }
-
private function getTariffPriceAt($tariffs, $typeSynonyms, $ts)
{
$wanted = array_map('strtolower', $typeSynonyms);
@@ -851,4 +944,4 @@ private function getDeltaFromArchive(int $varId, int $tStart, int $tEnd): float
return $path;
}
}
-?>
+?>
\ No newline at end of file