Files
Symcon_Belevo_Energiemanage…/Energy_Pie/module.html
T
2025-12-18 13:34:05 +01:00

251 lines
7.5 KiB
HTML
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.
<div id="wrap" style="padding:12px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;">
<!-- Controls -->
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;">
<label style="display:flex;gap:6px;align-items:center;">
<span>Zeitraum</span>
<select id="range">
<option value="day">Tag</option>
<option value="week">Woche</option>
<option value="month">Monat</option>
<option value="year">Jahr</option>
<option value="total">Gesamt</option>
</select>
</label>
<label style="display:flex;gap:6px;align-items:center;">
<span>Datum</span>
<input id="date" type="date" />
</label>
<button id="prev" type="button"></button>
<button id="today" type="button">Heute</button>
<button id="next" type="button"></button>
</div>
<div id="period" style="margin-top:10px;font-size:15px;font-weight:600;"></div>
<div id="hint" style="margin-top:6px;font-size:15px;font-weight:700;"></div>
<div id="grid"
style="margin-top:14px;
display:grid;
grid-template-columns:repeat(2,minmax(0,1fr));
gap:14px;">
</div>
<div id="explain"
style="margin-top:10px;
font-size:13px;
opacity:.75;
line-height:1.4;">
</div>
<div id="err" style="margin-top:8px;color:#ffb4b4;font-size:13px;"></div>
</div>
<style>
@media (max-width:720px){
#grid{grid-template-columns:1fr}
}
#wrap{
position:relative;
overflow:hidden;
min-height:100vh;
background:#121216;
}
#wrap::before{
content:"";
position:absolute;
inset:-35%;
background:
radial-gradient(520px 420px at 18% 18%, rgba(99,179,255,.42), transparent 60%),
radial-gradient(560px 460px at 82% 28%, rgba(168,85,247,.38), transparent 62%),
radial-gradient(620px 520px at 55% 85%, rgba(99,179,255,.26), transparent 64%);
filter:blur(18px);
pointer-events:none;
}
#wrap>*{position:relative;z-index:1}
#hint .kv{margin-right:14px;white-space:nowrap}
#hint .kv b{font-weight:900}
</style>
<script>
(function(){
const elRange = document.getElementById('range');
const elDate = document.getElementById('date');
const elPrev = document.getElementById('prev');
const elToday = document.getElementById('today');
const elNext = document.getElementById('next');
const elPeriod = document.getElementById('period');
const elHint = document.getElementById('hint');
const elGrid = document.getElementById('grid');
const elErr = document.getElementById('err');
function showErr(e){
elErr.textContent = e?.message || e;
}
function ra(){
return window.requestAction || window.parent?.requestAction || null;
}
function send(id,val){
const f = ra();
if(f) try{f(id,val)}catch(e){showErr(e)}
}
function fmt(d){
const p=n=>String(n).padStart(2,'0');
return `${p(d.getDate())}.${p(d.getMonth()+1)}.${d.getFullYear()}`;
}
function monthName(m){
return ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'][m];
}
function isoWeek(d){
d=new Date(Date.UTC(d.getFullYear(),d.getMonth(),d.getDate()));
d.setUTCDate(d.getUTCDate()+4-(d.getUTCDay()||7));
const y=d.getUTCFullYear();
const s=new Date(Date.UTC(y,0,1));
return Math.ceil((((d-s)/86400000)+1)/7)+" "+y;
}
function render(data) {
if (!data) return;
// UI-Status
elRange.value = data.range || 'day';
elDate.value = data.date || '';
elDate.disabled = (data.range === 'total');
// Zeitraum-Anzeige
if (data.range === 'total') {
elPeriod.textContent = '';
} else if (data.tStart && data.tEnd) {
const s = new Date(data.tStart * 1000);
const e = new Date(data.tEnd * 1000 - 1000);
const pad = n => String(n).padStart(2, '0');
const fmt = d => `${pad(d.getDate())}.${pad(d.getMonth() + 1)}.${d.getFullYear()}`;
if (data.range === 'day') {
elPeriod.textContent = `Zeitraum: ${fmt(s)}`;
} else if (data.range === 'week') {
elPeriod.textContent = `Zeitraum: ${fmt(s)} ${fmt(e)}`;
} else if (data.range === 'month') {
elPeriod.textContent = `Zeitraum: ${fmt(s)} ${fmt(e)}`;
} else if (data.range === 'year') {
elPeriod.textContent = `Zeitraum: ${fmt(s)} ${fmt(e)}`;
}
}
// Keine Daten vorhanden
if (data.hasData === false) {
elHint.innerHTML = `
<b>Letzter Zeitpunkt</b>
<span style="opacity:.7">(Keine Werte für diesen Zeitraum)</span>
`;
elGrid.innerHTML = '';
elExplain.innerHTML = '';
return;
}
// Werte
const v = data.values || {};
const prod = v.Produktion || 0;
const cons = v.Hausverbrauch || 0;
const grid = v.Netz || 0;
const eigen = Math.max(cons - grid, 0);
elHint.innerHTML = `
<span class="kv"><b>Produktion:</b> ${prod.toFixed(2)} kWh</span>
<span class="kv"><b>Verbrauch:</b> ${cons.toFixed(2)} kWh</span>
<span class="kv"><b>Netzbezug:</b> ${grid.toFixed(2)} kWh</span>
`;
// Donut-Renderer
const donut = (title, percent, color) => {
const r = 56;
const C = 2 * Math.PI * r;
const p = Math.max(0, Math.min(100, percent));
const dash = (p / 100) * C;
return `
<div style="text-align:center;display:flex;flex-direction:column;align-items:center;gap:10px;">
<div style="font-weight:900">${title}</div>
<div style="position:relative;width:160px;height:160px;">
<svg width="160" height="160" viewBox="0 0 160 160">
<circle cx="80" cy="80" r="${r}"
stroke="rgba(255,255,255,0.18)"
stroke-width="18"
fill="none" />
<circle cx="80" cy="80" r="${r}"
stroke="${color}"
stroke-width="18"
fill="none"
stroke-linecap="butt"
stroke-dasharray="${dash} ${C}"
transform="rotate(-90 80 80)"
style="filter: drop-shadow(0 0 12px ${color});" />
</svg>
<div style="position:absolute;inset:0;
display:flex;align-items:center;justify-content:center;
font-size:24px;font-weight:900;">
${p.toFixed(1)}%
</div>
</div>
</div>
`;
};
// Donuts einsetzen
elGrid.innerHTML =
donut('Eigenverbrauchsquote', prod ? (eigen / prod * 100) : 0, '#63B3FF') +
donut('Autarkiegrad', cons ? (eigen / cons * 100) : 0, '#A855F7');
// Erklärtexte unter den Kreisen
elExplain.innerHTML = `
<div>
<b>Eigenverbrauchsquote:</b>
Anteil des selbst erzeugten Stroms, der direkt im eigenen Haushalt verbraucht wird.
</div>
<div style="margin-top:6px;">
<b>Autarkiegrad:</b>
Anteil des gesamten Stromverbrauchs, der durch eigene Stromerzeugung gedeckt wird.
</div>
`;
}
document.getElementById('explain').innerHTML = `
<div>
<b>Eigenverbrauchsquote:</b>
Anteil des selbst erzeugten Stroms, der direkt im eigenen Haushalt verbraucht wird.
</div>
<div style="margin-top:6px;">
<b>Autarkiegrad:</b>
Anteil des gesamten Stromverbrauchs, der durch eigene Stromerzeugung gedeckt wird.
</div>
`;
window.handleMessage = d=>{
try{if(typeof d==='string')d=JSON.parse(d)}catch{}
render(d);
};
elRange.onchange = ()=>send('SetRange',elRange.value);
elDate.onchange = ()=>send('SetDate',elDate.value);
elPrev.onclick = ()=>send('Prev',1);
elNext.onclick = ()=>send('Next',1);
elToday.onclick = ()=>send('Today',1);
})();
</script>