Files
Symcon_Belevo_Energiemanage…/temp_mid.txt
T
2025-11-05 14:06:19 +01:00

191 lines
6.9 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
$type = $m['meter_type'] ?? 'Warmwasser';
$cost = $this->AddMeterToPDFRow($m, $tariffs, $from, $to, $type);
$html .= $cost['row'];
$total += $cost['value'];
}
$html .= "</table><h3>Gesamtsumme: " . number_format($total, 2) . " CHF</h3>";
$pdf->writeHTML($html);
}
IPS_LogMessage('Abrechnung', '✅ PDF-Daten fertiggestellt');
return $pdf->Output('Abrechnung.pdf', 'S');
} catch (Throwable $e) {
IPS_LogMessage('Abrechnung', '💥 Exception in TCPDF: ' . $e->getMessage());
return false;
}
}
private function AddMeterToPDF($pdf, $meter, $tariffs, $from, $to, $type)
{
$start = $this->GetValueAt($meter['var_consumption'], $from);
$end = $this->GetValueAt($meter['var_consumption'], $to);
if ($start === null || $end === null) return 0;
$diff = max(0, $end - $start);
$tariffRp = $this->GetTariff($tariffs, $type, $from, $to);
$cost = ($tariffRp / 100) * $diff;
$pdf->writeHTML("
<tr>
<td>{$meter['name']}</td>
<td>$type</td>
<td>$start</td>
<td>$end</td>
<td>$diff</td>
<td>$tariffRp</td>
<td>" . number_format($cost, 2) . "</td>
</tr>", false, false, false, false, '');
return $cost;
}
private function GetTariff(array $tariffs, string $type, int $from, int $to): float
{
foreach ($tariffs as $t) {
$start = strtotime($t['start']);
$end = strtotime($t['end']);
if ($from >= $start && $to <= $end && strtolower($t['unit_type']) == strtolower($type)) {
return floatval($t['price']);
}
}
// Kein passender Tarif gefunden
return 0.0;
}
private function GetValueAt(int $varId, int $timestamp, bool $nearestAfter = true)
{
$archiveID = @IPS_GetInstanceListByModuleID('{43192F0B-135B-4CE7-A0A7-1475603F3060}')[0];
if (!$archiveID || !IPS_VariableExists($varId)) {
IPS_LogMessage('Abrechnung', "❌ Variable $varId oder Archiv $archiveID nicht gefunden");
return null;
}
$maxDays = 365; // maximal 1 Jahr suchen
$stepDays = 30; // in 30-Tage-Blöcken durchsuchen
$valueFound = null;
if ($nearestAfter) {
// 🔹 Suche den ersten Wert NACH dem gewünschten Zeitpunkt
for ($offset = 0; $offset < $maxDays; $offset += $stepDays) {
$from = $timestamp + $offset * 86400;
$to = $from + $stepDays * 86400;
$values = @AC_GetLoggedValues($archiveID, $varId, $from, $to, 0);
if (!empty($values)) {
// ersten Wert nach Timestamp nehmen
foreach ($values as $v) {
if ($v['TimeStamp'] >= $timestamp) {
$valueFound = floatval($v['Value']);
break 2;
}
}
}
}
} else {
// 🔹 Suche den letzten Wert VOR dem gewünschten Zeitpunkt
for ($offset = 0; $offset < $maxDays; $offset += $stepDays) {
$from = $timestamp - ($offset + $stepDays) * 86400;
$to = $timestamp - $offset * 86400;
$values = @AC_GetLoggedValues($archiveID, $varId, $from, $to, 0);
if (!empty($values)) {
// letzten Wert vor Timestamp nehmen
$last = null;
foreach ($values as $v) {
if ($v['TimeStamp'] <= $timestamp) {
$last = $v;
} else {
break;
}
}
if ($last !== null) {
$valueFound = floatval($last['Value']);
break;
}
}
}
}
// 🔹 Falls nichts im Archiv: aktuellen Variablenwert nehmen
if ($valueFound === null) {
$fallback = floatval(GetValue($varId));
IPS_LogMessage('Abrechnung', "⚠ Kein Archivwert für $varId gefunden nutze aktuellen Wert ($fallback)");
return $fallback;
}
return $valueFound;
}
private function AddMeterToPDFRow($meter, $tariffs, $from, $to, $type)
{
$rows = '';
$totalCost = 0.0;
$varId = $meter['var_consumption'];
IPS_LogMessage('Abrechnung', "🔧 [AddMeterToPDFRow] Starte für '{$meter['name']}' (Typ: {$type}) von " . date('d.m.Y H:i', $from) . " bis " . date('d.m.Y H:i', $to));
if (!IPS_VariableExists($varId)) {
IPS_LogMessage('Abrechnung', "❌ Variable {$varId} für {$meter['name']} nicht gefunden");
return ['row' => '', 'value' => 0];
}
// Zeitzone setzen, um strtotime()-Abweichungen zu vermeiden
date_default_timezone_set('Europe/Zurich');
// 1️⃣ Relevante Tarife nach Typ filtern
$filteredTariffs = array_filter($tariffs, function ($t) use ($type) {
return strtolower(trim($t['unit_type'] ?? '')) === strtolower(trim($type));
});
if (empty($filteredTariffs)) {
IPS_LogMessage('Abrechnung', "⚠ Keine passenden Tarife für {$type} gefunden");
return ['row' => '', 'value' => 0];
}
// 2️⃣ Zeitstempel konvertieren, JSON-Objekte erkennen & sortieren
foreach ($filteredTariffs as &$t) {
// JSON-Fix: Start/Ende evtl. verschachtelt
if (is_string($t['start']) && str_starts_with(trim($t['start']), '{')) {
$s = json_decode($t['start'], true);
if (is_array($s)) {
$t['start'] = sprintf('%04d-%02d-%02d 00:00:00', $s['year'], $s['month'], $s['day']);
}
}
if (is_string($t['end']) && str_starts_with(trim($t['end']), '{')) {
$e = json_decode($t['end'], true);
if (is_array($e)) {
$t['end'] = sprintf('%04d-%02d-%02d 23:59:59', $e['year'], $e['month'], $e['day']);
}
}
$t['start_ts'] = is_numeric($t['start']) ? intval($t['start']) : strtotime($t['start']);
$t['end_ts'] = is_numeric($t['end']) ? intval($t['end']) : strtotime($t['end']);
if (!$t['start_ts'] || !$t['end_ts']) {
IPS_LogMessage('Abrechnung', "⚠ Ungültiger Tarifzeitraum: " . json_encode($t));
} else {
IPS_LogMessage('Abrechnung', sprintf(
" 🕓 Tarif gültig von %s bis %s @ %.3f Rp",
date('d.m.Y H:i', $t['start_ts']),
date('d.m.Y H:i', $t['end_ts']),
floatval($t['price'])
));
}
}
unset($t);
usort($filteredTariffs, fn($a, $b) => $a['start_ts'] <=> $b['start_ts']);
// 3️⃣ Abrechnungslogik
$currentStart = $from;
$segmentIndex = 1;
while ($currentStart < $to) {
IPS_LogMessage('Abrechnung', "➡️ Segment {$segmentIndex} Startzeit: " . date('d.m.Y H:i', $currentStart));
// 🔹 Aktiven Tarif bestimmen (FIX: <= auch am Ende erlaubt)
$activeTariff = null;