HAOS Add-on v1.1.1: Sparkline-Graphen (letzte 5 Minuten)

- SVG-Sparkline pro Sensor-Karte, farbkodiert nach device_class
- Backend: (timestamp, value) deque pro Sensor, API filtert auf 300s
- Kein Datenverlust bei Neustart (In-Memory, reicht für Trendanzeige)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
retr0
2026-04-26 12:14:24 +02:00
parent 35a3c01e36
commit 12586fa383
3 changed files with 42 additions and 1 deletions
+27
View File
@@ -64,6 +64,7 @@
.sensor-value { font-size: 20px; font-weight: 700;
font-variant-numeric: tabular-nums; }
.sensor-unit { font-size: 11px; color: var(--text-dim); margin-left: 2px; }
.sparkline { margin-top: 8px; opacity: .7; }
.dc-power .sensor-value { color: var(--accent); }
.dc-voltage .sensor-value { color: var(--blue); }
.dc-current .sensor-value { color: var(--orange); }
@@ -220,6 +221,30 @@
<div class="toast" id="toast"></div>
<script>
const DC_COLORS = {
power: '#f0c040', voltage: '#58a6ff', current: '#ffa657',
energy: '#3fb950', temperature: '#f85149', battery: '#bc8cff',
frequency: '#8b949e', default: '#8b949e',
};
function sparkline(values, dc) {
if (!values || values.length < 2) return '';
const color = DC_COLORS[dc] || DC_COLORS.default;
const min = Math.min(...values);
const max = Math.max(...values);
const range = max - min || 1;
const W = 138, H = 28, pad = 1;
const pts = values.map((v, i) => {
const x = pad + (i / (values.length - 1)) * (W - pad * 2);
const y = pad + (1 - (v - min) / range) * (H - pad * 2);
return `${x.toFixed(1)},${y.toFixed(1)}`;
}).join(' ');
return `<svg class="sparkline" width="${W}" height="${H}" viewBox="0 0 ${W} ${H}">
<polyline points="${pts}" fill="none" stroke="${color}"
stroke-width="1.5" stroke-linejoin="round" stroke-linecap="round"/>
</svg>`;
}
const ICON_MAP = {
"mdi:solar-panel":"☀️","mdi:flash":"⚡","mdi:sine-wave":"〜",
"mdi:solar-power":"🔆","mdi:thermometer":"🌡️","mdi:battery":"🔋",
@@ -286,10 +311,12 @@ function renderLive(inverters) {
const val = inv.values[s.id];
const display = val !== undefined ? fmtVal(val) : "—";
const dcClass = s.device_class ? `dc-${s.device_class}` : "";
const hist = (inv.history || {})[s.id] || [];
return `<div class="sensor-card ${dcClass}">
<div class="sensor-icon">${ICON_MAP[s.icon]||"📊"}</div>
<div class="sensor-name">${s.name}</div>
<div class="sensor-value">${display}<span class="sensor-unit">${s.unit}</span></div>
${sparkline(hist, s.device_class)}
</div>`;
}).join("");
return `<div class="inv-section">