From 78be02d5076c45c7c4d61d4cb63396225a30eaa8 Mon Sep 17 00:00:00 2001 From: "belevo\\mh" Date: Wed, 17 Dec 2025 13:47:41 +0100 Subject: [PATCH] no message --- Energy_Pie/module.php | 198 +++++++++++++++++------------------------- 1 file changed, 80 insertions(+), 118 deletions(-) diff --git a/Energy_Pie/module.php b/Energy_Pie/module.php index 605908a..8000589 100644 --- a/Energy_Pie/module.php +++ b/Energy_Pie/module.php @@ -4,7 +4,6 @@ declare(strict_types=1); class Energy_Pie extends IPSModule { - // Attribute keys for UI state private const ATTR_RANGE = 'Range'; private const ATTR_DATE = 'Date'; @@ -18,35 +17,37 @@ class Energy_Pie extends IPSModule $this->RegisterPropertyInteger('VarFeedIn', 0); $this->RegisterPropertyInteger('VarGrid', 0); - // Default range for first startup - $this->RegisterPropertyString('DefaultRange', 'day'); - // Persisted UI state $this->RegisterAttributeString(self::ATTR_RANGE, 'day'); $this->RegisterAttributeString(self::ATTR_DATE, date('Y-m-d')); // Enable individual visualization (HTML-SDK) $this->SetVisualizationType(1); + + // IMPORTANT: Timer calls global helper below (must exist!) + $this->RegisterTimer('AutoPush', 0, 'EP_AutoPush($_IPS["TARGET"]);'); } public function ApplyChanges(): void { parent::ApplyChanges(); - // First-time init: if range is empty, set it to property default + // ensure range valid $range = $this->ReadAttributeString(self::ATTR_RANGE); - if ($range === '') { - $this->WriteAttributeString(self::ATTR_RANGE, $this->ReadPropertyString('DefaultRange')); + if (!in_array($range, ['day', 'week', 'month', 'total'], true)) { + $this->WriteAttributeString(self::ATTR_RANGE, 'day'); } + // ensure date valid (not empty/invalid/future) $date = $this->ReadAttributeString(self::ATTR_DATE); - - // Wenn Datum leer/ungültig oder in der Zukunft -> heute setzen if ($date === '' || !$this->isValidDate($date) || strtotime($date . ' 00:00:00') > time()) { $this->WriteAttributeString(self::ATTR_DATE, date('Y-m-d')); } - // Push initial view data + // Fullscreen-Fix: push periodically (adjust as you like) + // 2000ms = alle 2 Sekunden (stabil, aber nicht ganz so brutal wie 1000ms) + $this->SetTimerInterval('AutoPush', 2000); + $this->RecalculateAndPush(); } @@ -65,17 +66,16 @@ class Energy_Pie extends IPSModule case 'SetRange': $range = (string)$Value; if (!in_array($range, ['day', 'week', 'month', 'total'], true)) { - throw new Exception('Invalid range: ' . $range); + return; } $this->WriteAttributeString(self::ATTR_RANGE, $range); $this->RecalculateAndPush(); break; case 'SetDate': - // Expect YYYY-MM-DD from HTML $date = (string)$Value; if (!$this->isValidDate($date)) { - throw new Exception('Invalid date: ' . $date); + return; } $this->WriteAttributeString(self::ATTR_DATE, $date); $this->RecalculateAndPush(); @@ -93,118 +93,90 @@ class Energy_Pie extends IPSModule break; default: - throw new Exception('Unknown Ident: ' . $Ident); + // ignore unknown + return; } } - /** - * Compute values (later from archive), then push to tile via UpdateVisualizationValue. - */ -private function RecalculateAndPush(): void -{ + private function RecalculateAndPush(): void + { + $range = $this->ReadAttributeString(self::ATTR_RANGE); + $date = $this->ReadAttributeString(self::ATTR_DATE); + [$tStart, $tEnd] = $this->getRange($range, $date); + $dbgProd = []; + $dbgFeed = []; + $dbgGrid = []; - $range = $this->ReadAttributeString(self::ATTR_RANGE); - $date = $this->ReadAttributeString(self::ATTR_DATE); + $prod = $this->readDelta($this->ReadPropertyInteger('VarProduction'), $tStart, $tEnd, $dbgProd); + $feed = $this->readDelta($this->ReadPropertyInteger('VarFeedIn'), $tStart, $tEnd, $dbgFeed); + $grid = $this->readDelta($this->ReadPropertyInteger('VarGrid'), $tStart, $tEnd, $dbgGrid); - + $hasData = (($dbgProd['count'] ?? 0) > 0) || (($dbgFeed['count'] ?? 0) > 0) || (($dbgGrid['count'] ?? 0) > 0); - [$tStart, $tEnd] = $this->getRange($range, $date); + // Auto-jump to last log day if none found + if (!$hasData && $range !== 'total') { + $lastTs = $this->getLastLogTimestamp($this->ReadPropertyInteger('VarProduction')); + if ($lastTs > 0) { + $this->WriteAttributeString(self::ATTR_DATE, date('Y-m-d', $lastTs)); + $date = $this->ReadAttributeString(self::ATTR_DATE); - // Debug-Container initialisieren (sonst "Undefined variable") - $dbgProd = []; - $dbgFeed = []; - $dbgGrid = []; + [$tStart, $tEnd] = $this->getRange($range, $date); - $prod = $this->readDelta($this->ReadPropertyInteger('VarProduction'), $tStart, $tEnd, $dbgProd); - $feed = $this->readDelta($this->ReadPropertyInteger('VarFeedIn'), $tStart, $tEnd, $dbgFeed); - $grid = $this->readDelta($this->ReadPropertyInteger('VarGrid'), $tStart, $tEnd, $dbgGrid); + $prod = $this->readDelta($this->ReadPropertyInteger('VarProduction'), $tStart, $tEnd, $dbgProd); + $feed = $this->readDelta($this->ReadPropertyInteger('VarFeedIn'), $tStart, $tEnd, $dbgFeed); + $grid = $this->readDelta($this->ReadPropertyInteger('VarGrid'), $tStart, $tEnd, $dbgGrid); - - $hasData = (($dbgProd['count'] ?? 0) > 0) || (($dbgFeed['count'] ?? 0) > 0) || (($dbgGrid['count'] ?? 0) > 0); - - if (!$hasData && $range !== 'total') { - // nimm Produktion als Referenz für "letzte Daten" - $lastTs = $this->getLastLogTimestamp($this->ReadPropertyInteger('VarProduction')); - - if ($lastTs > 0) { - $this->WriteAttributeString(self::ATTR_DATE, date('Y-m-d', $lastTs)); - - // Range neu berechnen für dieses Datum - $date = $this->ReadAttributeString(self::ATTR_DATE); - [$tStart, $tEnd] = $this->getRange($range, $date); - - // Deltas nochmal holen (jetzt sollte count>0 werden) - $prod = $this->readDelta($this->ReadPropertyInteger('VarProduction'), $tStart, $tEnd, $dbgProd); - $feed = $this->readDelta($this->ReadPropertyInteger('VarFeedIn'), $tStart, $tEnd, $dbgFeed); - $grid = $this->readDelta($this->ReadPropertyInteger('VarGrid'), $tStart, $tEnd, $dbgGrid); - - $hasData = (($dbgProd['count'] ?? 0) > 0) || (($dbgFeed['count'] ?? 0) > 0) || (($dbgGrid['count'] ?? 0) > 0); + $hasData = (($dbgProd['count'] ?? 0) > 0) || (($dbgFeed['count'] ?? 0) > 0) || (($dbgGrid['count'] ?? 0) > 0); + } } + + // House = Prod - Feed + Grid + $house = $prod - $feed + $grid; + if ($house < 0) $house = 0.0; + + $payload = [ + 'range' => $range, + 'date' => $date, + 'tStart' => $tStart, + 'tEnd' => $tEnd, + 'hasData' => $hasData, + 'values' => [ + 'Produktion' => (float)$prod, + 'Einspeisung' => (float)$feed, + 'Netz' => (float)$grid, + 'Hausverbrauch' => (float)$house + ], + // kannst du später entfernen + 'debug' => [ + 'prod' => $dbgProd, + 'feed' => $dbgFeed, + 'grid' => $dbgGrid + ] + ]; + + $this->UpdateVisualizationValue(json_encode($payload, JSON_THROW_ON_ERROR)); } - - $house = $prod - $feed + $grid; - if ($house < 0) $house = 0.0; - - $payload = [ - 'range' => $range, - 'date' => $date, - 'tStart' => $tStart, - 'tEnd' => $tEnd, - 'hasData' => $hasData, - 'values' => [ - 'Produktion' => (float)$prod, - 'Einspeisung' => (float)$feed, - 'Netz' => (float)$grid, - 'Hausverbrauch' => (float)$house - ], - 'debug' => [ - 'prod' => $dbgProd, - 'feed' => $dbgFeed, - 'grid' => $dbgGrid - ] - ]; - - $this->UpdateVisualizationValue(json_encode($payload, JSON_THROW_ON_ERROR)); -} - - - /** - * Range rules: - * - day: chosen date 00:00:00 .. next day 00:00:00 - * - week: Monday 00:00:00 .. next Monday 00:00:00 (Mo–So) - * - month: first of month 00:00:00 .. first of next month 00:00:00 - * - total: 0 .. now (placeholder) - */ private function getRange(string $range, string $dateYmd): array { $now = time(); if ($range === 'total') { - // Later: use oldest log timestamp as start return [0, $now]; } - $base = strtotime($dateYmd . ' 00:00:00'); - if ($base === false) { - // fallback to today - $base = strtotime(date('Y-m-d') . ' 00:00:00'); - } + $base = strtotime($dateYmd . ' 00:00:00') ?: strtotime(date('Y-m-d') . ' 00:00:00'); switch ($range) { case 'day': - $start = $base; - $end = $start + 86400; - return [$start, $end]; + return [$base, $base + 86400]; case 'week': - // date('N'): 1=Mon .. 7=Sun - $dow = (int)date('N', $base); - $start = $base - (($dow - 1) * 86400); // Monday - $end = $start + (7 * 86400); // next Monday - return [$start, $end]; + $dow = (int)date('N', $base); // 1=Mon..7=Sun + $start = $base - (($dow - 1) * 86400); + return [$start, $start + 7 * 86400]; case 'month': $start = strtotime(date('Y-m-01 00:00:00', $base)); @@ -216,7 +188,6 @@ private function RecalculateAndPush(): void } } - private function readDelta(int $varId, int $tStart, int $tEnd, array &$dbg): float { $dbg = [ @@ -235,7 +206,6 @@ private function RecalculateAndPush(): void $archiveID = IPS_GetInstanceListByModuleID('{43192F0B-135B-4CE7-A0A7-1475603F3060}')[0] ?? 0; $dbg['archiveId'] = $archiveID; - if ($archiveID <= 0) { return 0.0; } @@ -282,27 +252,18 @@ private function RecalculateAndPush(): void return 0; } - // Hole den letzten Eintrag (0..now, limit=1 -> der neueste) $values = @AC_GetLoggedValues($archiveID, $varId, 0, time(), 1); if (empty($values)) { return 0; } - - // Bei limit=1 kommt genau ein Eintrag (der neueste) return (int)$values[0]['TimeStamp']; } - - - /** - * Buttons for quick navigation. - */ private function ShiftDate(string $action): void { $range = $this->ReadAttributeString(self::ATTR_RANGE); if ($range === 'total') { - // total ignores date return; } @@ -312,10 +273,7 @@ private function RecalculateAndPush(): void } $date = $this->ReadAttributeString(self::ATTR_DATE); - $base = strtotime($date . ' 00:00:00'); - if ($base === false) { - $base = strtotime(date('Y-m-d') . ' 00:00:00'); - } + $base = strtotime($date . ' 00:00:00') ?: strtotime(date('Y-m-d') . ' 00:00:00'); $sign = ($action === 'Prev') ? -1 : 1; @@ -323,11 +281,9 @@ private function RecalculateAndPush(): void case 'day': $base = strtotime(($sign === -1 ? '-1 day' : '+1 day'), $base); break; - case 'week': $base = strtotime(($sign === -1 ? '-7 day' : '+7 day'), $base); break; - case 'month': $base = strtotime(($sign === -1 ? '-1 month' : '+1 month'), $base); break; @@ -338,15 +294,21 @@ private function RecalculateAndPush(): void private function isValidDate(string $ymd): bool { - // expects YYYY-MM-DD if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $ymd)) { return false; } [$y, $m, $d] = array_map('intval', explode('-', $ymd)); return checkdate($m, $d, $y); } - - } +/** + * Timer callback (must exist, because RegisterTimer uses it). + * We keep it super simple and robust: + * -> just trigger Refresh, which recalculates + pushes the payload. + */ +function EP_AutoPush(int $id): void +{ + @IPS_RequestAction($id, 'Refresh', 1); +} ?> \ No newline at end of file