Feature: Flexibler Stromtarif (Börsenstrom) in Einstellungen + Periodenabrechnung (v1.8.1)
- Tarifart: Festpreis / Flexibel (Börsenstrom) — Radio-Toggle in Einstellungen - Flexibel: Aufschlag (ct/kWh) + Land (DE/AT) konfigurierbar - /api/period-energy: bei tariff_type=spot → historische aWATTar-Preise, 1h Cache - Kostenrechnung Monat/Jahr: Ø Börsenpreis + Aufschlag statt Festpreis - Periodenkarte zeigt "Ø X.X + Y.Y ct/kWh" bei Börsentarif - Spot-Chart-Toggle in Einstellungen (spot_chart true/false) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -208,11 +208,40 @@
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h3>Strompreise</h3>
|
||||
<div class="field"><label>Bezugspreis (€/kWh)</label>
|
||||
<input type="number" id="cfg-price-import" step="0.001" placeholder="0.300"></div>
|
||||
<h3>Stromtarif</h3>
|
||||
<div class="field">
|
||||
<label>Tarifart</label>
|
||||
<div style="display:flex;gap:16px;margin-top:4px">
|
||||
<label style="cursor:pointer;display:flex;align-items:center;gap:6px;font-size:13px">
|
||||
<input type="radio" name="tariff-type" value="fixed" id="tariff-fixed" onchange="updateTariffUI()"> Festpreis
|
||||
</label>
|
||||
<label style="cursor:pointer;display:flex;align-items:center;gap:6px;font-size:13px">
|
||||
<input type="radio" name="tariff-type" value="spot" id="tariff-spot" onchange="updateTariffUI()"> Flexibel (Börsenstrom)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tariff-fixed-fields">
|
||||
<div class="field"><label>Bezugspreis (€/kWh)</label>
|
||||
<input type="number" id="cfg-price-import" step="0.001" placeholder="0.300"></div>
|
||||
</div>
|
||||
<div id="tariff-spot-fields" style="display:none">
|
||||
<div class="field"><label>Aufschlag Netz + Steuern (ct/kWh)</label>
|
||||
<input type="number" id="cfg-spot-markup" step="0.1" placeholder="15.0">
|
||||
<div style="font-size:11px;color:var(--text-dim);margin-top:4px">Netzentgelt + Steuern + Aufschlag Anbieter — wird auf den Börsenpreis addiert</div>
|
||||
</div>
|
||||
<div class="field"><label>Land</label>
|
||||
<select id="cfg-spot-country" style="background:var(--surface);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px;padding:6px 10px;outline:none">
|
||||
<option value="de">Deutschland</option>
|
||||
<option value="at">Österreich</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field"><label>Einspeisevergütung (€/kWh)</label>
|
||||
<input type="number" id="cfg-price-export" step="0.001" placeholder="0.080"></div>
|
||||
<div class="field" style="display:flex;align-items:center;gap:8px">
|
||||
<input type="checkbox" id="cfg-spot-chart" style="width:auto;margin:0">
|
||||
<label for="cfg-spot-chart" style="margin:0;cursor:pointer;font-size:13px">Börsenstrompreis-Chart anzeigen</label>
|
||||
</div>
|
||||
<div class="field"><label>Abrechnungsjahr beginnt am</label>
|
||||
<div style="display:flex;gap:8px;align-items:center">
|
||||
<input type="number" id="cfg-billing-day" min="1" max="28" placeholder="1" style="width:72px">
|
||||
@@ -576,8 +605,11 @@ function renderEnergy(inverters, aggregates, period, spotData) {
|
||||
}
|
||||
|
||||
function sectionCards(title, data, col) {
|
||||
const imp = periodCard('Netzbezug', data.grid_import_kwh, data.import_cost, C.imp, '');
|
||||
const exp = periodCard('Einspeisung', data.grid_export_kwh, data.export_revenue, C.exp, '');
|
||||
const impSub = data.spot_avg_ct != null
|
||||
? `Ø ${data.spot_avg_ct.toFixed(1)} + ${(data.spot_markup_ct||0).toFixed(1)} ct/kWh`
|
||||
: '';
|
||||
const imp = periodCard('Netzbezug', data.grid_import_kwh, data.import_cost, C.imp, impSub);
|
||||
const exp = periodCard('Einspeisung', data.grid_export_kwh, data.export_revenue, C.exp, '');
|
||||
if (!imp && !exp) return '';
|
||||
return `<div style="margin-bottom:8px;font-size:10px;font-weight:700;letter-spacing:.08em;color:${C.dim};text-transform:uppercase">${title}</div>
|
||||
<div class="energy-kwh" style="margin-bottom:16px">${imp}${exp}</div>`;
|
||||
@@ -586,7 +618,7 @@ function renderEnergy(inverters, aggregates, period, spotData) {
|
||||
const cards = sectionCards(mon.label || 'Diesen Monat', mon, C.imp) +
|
||||
sectionCards(yr.label || 'Dieses Jahr', yr, C.imp);
|
||||
|
||||
const spotHtml = renderSpotChart(spotData);
|
||||
const spotHtml = (period.spot_chart !== false) ? renderSpotChart(spotData) : '';
|
||||
|
||||
el.innerHTML = `<div class="energy-wrap">
|
||||
<div class="energy-svg-wrap">${svg}${spotHtml}</div>
|
||||
@@ -822,21 +854,38 @@ async function deleteInverter(id) {
|
||||
|
||||
// ── MQTT Settings ─────────────────────────────────────────────
|
||||
|
||||
function updateTariffUI() {
|
||||
const isSpot = document.getElementById("tariff-spot").checked;
|
||||
document.getElementById("tariff-fixed-fields").style.display = isSpot ? "none" : "";
|
||||
document.getElementById("tariff-spot-fields").style.display = isSpot ? "" : "none";
|
||||
}
|
||||
|
||||
async function loadSettings() {
|
||||
globalConfig = await fetchJSON(api("api/config"));
|
||||
document.getElementById("cfg-mqtt-broker").value = globalConfig.mqtt_broker || "";
|
||||
document.getElementById("cfg-mqtt-port").value = globalConfig.mqtt_port || 1883;
|
||||
document.getElementById("cfg-mqtt-user").value = globalConfig.mqtt_user || "";
|
||||
document.getElementById("cfg-price-import").value = globalConfig.price_import ?? 0.30;
|
||||
document.getElementById("cfg-price-export").value = globalConfig.price_export ?? 0.08;
|
||||
document.getElementById("cfg-billing-day").value = globalConfig.billing_day ?? 1;
|
||||
document.getElementById("cfg-billing-month").value = globalConfig.billing_month ?? 1;
|
||||
const cfg = await fetchJSON(api("api/config"));
|
||||
globalConfig = cfg;
|
||||
document.getElementById("cfg-mqtt-broker").value = cfg.mqtt_broker || "";
|
||||
document.getElementById("cfg-mqtt-port").value = cfg.mqtt_port || 1883;
|
||||
document.getElementById("cfg-mqtt-user").value = cfg.mqtt_user || "";
|
||||
document.getElementById("cfg-price-import").value = cfg.price_import ?? 0.30;
|
||||
document.getElementById("cfg-price-export").value = cfg.price_export ?? 0.08;
|
||||
document.getElementById("cfg-billing-day").value = cfg.billing_day ?? 1;
|
||||
document.getElementById("cfg-billing-month").value = cfg.billing_month ?? 1;
|
||||
document.getElementById("cfg-spot-markup").value = cfg.spot_markup ?? 0.0;
|
||||
document.getElementById("cfg-spot-country").value = cfg.spot_country ?? "de";
|
||||
document.getElementById("cfg-spot-chart").checked = cfg.spot_chart ?? true;
|
||||
document.getElementById((cfg.tariff_type ?? "fixed") === "spot" ? "tariff-spot" : "tariff-fixed").checked = true;
|
||||
updateTariffUI();
|
||||
}
|
||||
|
||||
async function savePrices() {
|
||||
const isSpot = document.getElementById("tariff-spot").checked;
|
||||
const body = {
|
||||
price_import: parseFloat(document.getElementById("cfg-price-import").value),
|
||||
price_export: parseFloat(document.getElementById("cfg-price-export").value),
|
||||
tariff_type: isSpot ? "spot" : "fixed",
|
||||
price_import: parseFloat(document.getElementById("cfg-price-import").value || 0.30),
|
||||
price_export: parseFloat(document.getElementById("cfg-price-export").value || 0.08),
|
||||
spot_markup: parseFloat(document.getElementById("cfg-spot-markup").value || 0),
|
||||
spot_country: document.getElementById("cfg-spot-country").value,
|
||||
spot_chart: document.getElementById("cfg-spot-chart").checked,
|
||||
billing_day: parseInt(document.getElementById("cfg-billing-day").value),
|
||||
billing_month: parseInt(document.getElementById("cfg-billing-month").value),
|
||||
};
|
||||
@@ -845,7 +894,7 @@ async function savePrices() {
|
||||
method: "POST", headers: {"Content-Type": "application/json"},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
showToast("Preise gespeichert", "ok");
|
||||
showToast("Einstellungen gespeichert", "ok");
|
||||
} catch(e) {
|
||||
showToast("Fehler beim Speichern", "err");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user