From b6a1625433f549d5fc83bb0ae6c2e81c99019957 Mon Sep 17 00:00:00 2001 From: "belevo\\mh" Date: Wed, 17 Dec 2025 08:18:44 +0100 Subject: [PATCH] no message --- Energy_Pie/module.html | 121 ++++++++++++----------------------------- Energy_Pie/module.php | 61 ++++++++++----------- 2 files changed, 66 insertions(+), 116 deletions(-) diff --git a/Energy_Pie/module.html b/Energy_Pie/module.html index 085085d..fd5c82e 100644 --- a/Energy_Pie/module.html +++ b/Energy_Pie/module.html @@ -15,21 +15,16 @@ - + - + -
-
- -
-
+
-
-
Aufteilung
-
-
+
+
Werte
+
@@ -39,30 +34,27 @@ const elPrev = document.getElementById('prev'); const elToday = document.getElementById('today'); const elNext = document.getElementById('next'); - const elLegend = document.getElementById('legend'); + const elValues = document.getElementById('values'); const elPeriod = document.getElementById('period'); - const canvas = document.getElementById('pie'); - const ctx = canvas.getContext('2d'); - + // Range ändern -> sofort rechnen elRange.addEventListener('change', () => requestAction('SetRange', elRange.value)); - // Fire immediately when user picks a date (input + change), with a tiny debounce + // Datum ändern -> sofort rechnen (input + change, mit kleinem debounce) let dateTimer = null; function pushDateNow() { if (dateTimer) clearTimeout(dateTimer); - dateTimer = setTimeout(() => { - requestAction('SetDate', elDate.value); - }, 80); + dateTimer = setTimeout(() => requestAction('SetDate', elDate.value), 80); } elDate.addEventListener('input', pushDateNow); elDate.addEventListener('change', pushDateNow); + // Navigation elPrev.addEventListener('click', () => requestAction('Prev', 1)); elToday.addEventListener('click', () => requestAction('Today', 1)); elNext.addEventListener('click', () => requestAction('Next', 1)); - // Called by Symcon when PHP sends UpdateVisualizationValue($payload) + // Symcon pusht Daten hier rein (UpdateVisualizationValue -> handleMessage) function handleMessage(data) { if (!data) return; @@ -72,6 +64,7 @@ const isTotal = (data.range === 'total'); elDate.disabled = isTotal; + // Zeitraum-Text if (data.tStart && data.tEnd) { const s = new Date(data.tStart * 1000); const e = new Date(data.tEnd * 1000); @@ -82,12 +75,30 @@ elPeriod.textContent = ''; } + // Werte-Box if (data.values) { - drawPie(data.values); - drawLegend(data.values); + renderValues(data.values); + } else { + renderValues({}); } } + // Nur diese vier Werte anzeigen (fixe Reihenfolge) + function renderValues(values) { + const order = ['Produktion', 'Einspeisung', 'Netz', 'Hausverbrauch']; + + elValues.innerHTML = order.map((k) => { + const v = values?.[k]; + const val = (+v || 0); + return ` +
+
${escapeHtml(k)}
+
${val.toFixed(2)} kWh
+
+ `; + }).join(''); + } + function fmtDateTime(d) { const yyyy = d.getFullYear(); const mm = String(d.getMonth() + 1).padStart(2,'0'); @@ -97,69 +108,6 @@ return `${dd}.${mm}.${yyyy} ${hh}:${mi}`; } - function drawLegend(values) { - const entries = Object.entries(values); - const sum = entries.reduce((a,[,v]) => a + (+v || 0), 0); - - elLegend.innerHTML = entries.map(([k,v]) => { - const val = (+v || 0); - const pct = sum > 0 ? (val / sum * 100) : 0; - return ` -
-
${escapeHtml(k)}
-
${val.toFixed(2)} kWh (${pct.toFixed(1)}%)
-
`; - }).join(''); - } - - function drawPie(values) { - const entries = Object.entries(values).map(([k,v]) => [k, (+v || 0)]); - const sum = entries.reduce((a,[,v]) => a + v, 0); - - ctx.clearRect(0,0,canvas.width,canvas.height); - - // Background circle - ctx.beginPath(); - ctx.arc(140,140,125,0,Math.PI*2); - ctx.fillStyle = '#f2f2f2'; - ctx.fill(); - - if (sum <= 0) { - ctx.fillStyle = '#666'; - ctx.font = '14px sans-serif'; - ctx.fillText('Keine Daten', 92, 145); - return; - } - - let start = -Math.PI / 2; - const colors = ['#4e79a7','#f28e2b','#e15759','#76b7b2','#59a14f','#edc948']; - - entries.forEach(([label,val], i) => { - if (val <= 0) return; - const ang = (val / sum) * Math.PI * 2; - ctx.beginPath(); - ctx.moveTo(140,140); - ctx.arc(140,140,125,start,start+ang); - ctx.closePath(); - ctx.fillStyle = colors[i % colors.length]; - ctx.fill(); - start += ang; - }); - - // Donut hole - ctx.beginPath(); - ctx.arc(140,140,65,0,Math.PI*2); - ctx.fillStyle = '#fff'; - ctx.fill(); - - // Sum in center - ctx.fillStyle = '#111'; - ctx.font = 'bold 16px sans-serif'; - const text = sum.toFixed(2) + ' kWh'; - const w = ctx.measureText(text).width; - ctx.fillText(text, 140 - w/2, 146); - } - function escapeHtml(s) { return String(s) .replaceAll('&','&') @@ -168,4 +116,7 @@ .replaceAll('"','"') .replaceAll("'",'''); } + + // Beim Laden direkt einmal Werte anfordern, damit sofort etwas angezeigt wird + setTimeout(() => requestAction('Refresh', 1), 200); diff --git a/Energy_Pie/module.php b/Energy_Pie/module.php index 0ac8c13..45de3cf 100644 --- a/Energy_Pie/module.php +++ b/Energy_Pie/module.php @@ -93,42 +93,41 @@ class Energy_Pie extends IPSModule /** * Compute values (later from archive), then push to tile via UpdateVisualizationValue. */ - private function RecalculateAndPush(): void - { - $range = $this->ReadAttributeString(self::ATTR_RANGE); - $date = $this->ReadAttributeString(self::ATTR_DATE); +private function RecalculateAndPush(): void +{ + $range = $this->ReadAttributeString(self::ATTR_RANGE); + $date = $this->ReadAttributeString(self::ATTR_DATE); - [$tStart, $tEnd] = $this->getRange($range, $date); + [$tStart, $tEnd] = $this->getRange($range, $date); - // --- PLACEHOLDER CALCULATION --- - // Replace these with your later delta calculation from logged data: - // $prod = $this->readDelta($this->ReadPropertyInteger('VarProduction'), $tStart, $tEnd); - // etc. - $prod = 12.3; - $cons = 8.7; - $feed = 3.1; - $grid = 5.6; - - // If you prefer, you can already set them to 0.0 for "no calc yet" - // $prod = $cons = $feed = $grid = 0.0; - - $payload = [ - 'range' => $range, - 'date' => $date, - 'tStart' => $tStart, - 'tEnd' => $tEnd, - 'values' => [ - 'Produktion' => (float)$prod, - 'Verbrauch' => (float)$cons, - 'Einspeisung' => (float)$feed, - 'Netz' => (float)$grid - ] - ]; - - $this->UpdateVisualizationValue(json_encode($payload, JSON_THROW_ON_ERROR)); + // Archiv-Deltas + $prod = $this->readDelta($this->ReadPropertyInteger('VarProduction'), $tStart, $tEnd); + $feed = $this->readDelta($this->ReadPropertyInteger('VarFeedIn'), $tStart, $tEnd); + $grid = $this->readDelta($this->ReadPropertyInteger('VarGrid'), $tStart, $tEnd); + // Hausverbrauch = Produktion - Einspeisung + Netz + $house = $prod - $feed + $grid; + if ($house < 0) { + $house = 0.0; } + $payload = [ + 'range' => $range, + 'date' => $date, + 'tStart' => $tStart, + 'tEnd' => $tEnd, + 'values' => [ + 'Produktion' => (float)$prod, + 'Einspeisung' => (float)$feed, + 'Netz' => (float)$grid, + 'Hausverbrauch'=> (float)$house + ] + ]; + + $this->UpdateVisualizationValue(json_encode($payload, JSON_THROW_ON_ERROR)); +} + + /** * Range rules: * - day: chosen date 00:00:00 .. next day 00:00:00