NEWS
[Neuer Adapter] Senec Home Adapter
-
Ich auch Bescheid, bitte
-
-
Erst einmal vielen Dank für das Script.
Leider bekomme ich einen Fehler beim Starten vom Script.
javascript.0 08:39:18.506 info Start JavaScript script.js.Energie_Strom.Senec.senec_tageswerte (Javascript/js) javascript.0 08:39:18.543 error ReferenceError: createChannel is not defined javascript.0 08:39:18.543 error at script.js.Energie_Strom.Senec.senec_tageswerte:48:4 javascript.0 08:39:18.544 error at script.js.Energie_Strom.Senec.senec_tageswerte:174:3
-
@icebear Ich bekomme den gleichen Fehler.
-
@oxident
Wenn ihr das Skript nochmal startet - taucht der Fehler dann wieder auf? Oder nur beim Initial Start? -
Der Fehler kommt auch nach einem erneuten Start des Script.
-
@dispo112 Der Fehler kommt immer wieder.
-
@semmy Seltsam, hatte alle Fehler behoben und es jetzt 1:1 bei mir herauskopiert.
Schaue ich mir nachher an!
-
Ich glaub es reicht wenn du 'createChannel' durch 'createState' ersetzt.
// --- Ordner (Channel) anlegen, falls nicht vorhanden --- if (!existsObject(BASE_DP_PATH)) { createState(BASE_DP_PATH, 'Ordner für Energie-Datenpunkte', (err) => { if (err) { log(`Fehler beim Erstellen des Ordners ${BASE_DP_PATH}: ${err}`, 'error'); } else { log(`Ordner ${BASE_DP_PATH} erfolgreich erstellt`, 'info'); } }); }
-
Ok, funktioniert jetzt. Wie bekommt man die Datenpunkte in Home Assistant?
Viele Grüße
Semmy -
@semmy said in [Neuer Adapter] Senec Home Adapter:
Wie bekommt man die Datenpunkte in Home Assistant?
Also ich mach das bei einem anderen Projekt mit MQTT.
-
@dispo112 said in [Neuer Adapter] Senec Home Adapter:
So, bitte schön. Die Ordnerpfade sind alle standard. Theoretisch könnt ihr das Skript importieren und starten, fertig. Alle neuen Datenpunkte werden im Userdata erzeugt und können dann via Lovelace / VIS abgegriffen werden.
Nochmal vielen Dank für deine Arbeit. Läuft bei mir seit gestern und die Werte sind soweit völlig O.K.
Ich hab mich jetzt auch entschieden, nicht mehr darauf zu Warten ob irgendeiner etwas bereitstellt das die API oder die Werte über mein-senec abgegriffen werden. Die Klimzüge über HA sind mir zu aufwendig und keiner weiß wie lange das dann funktioniert bevor Senec da wieder den Riegel vorschiebt.
Solange wie der Adapter mir die Live-Daten zur Verfügung stellt reicht mir das.Ich hab deshalb zusätzlich zu dem Script von @dispo112 noch drei weitere Scripte bei mir implementiert, die laufen seit gestern und liefern meines Erachtens ausreichend genaue Werte, so das sich eine gewisse Statistik aufrechterhalten lässt.
Hier die drei Scripte die ich zusätzlich noch implementiert hab:
- Hausverbrauch (schreibt die Werte in zwei DP's , einmal Wh und einmal kWh und wird täglich um 00:00 Uhr auf '0' gesetzt)
// ====== Konfiguration START ====== // ID des Datenpunkts, der den aktuellen Hausverbrauch in Watt (W) liefert. // Diesen Wert MUSST du an deine ioBroker-Installation anpassen! // Beispiel: 'shelly.0.shellypower.power' oder 'modbus.0.holdingRegisters.power_total' const currentHouseConsumptionPowerId = "senec.0.ENERGY.GUI_HOUSE_POW"; // ID des Datenpunkts für den täglichen Hausverbrauch in Wh (wird erstellt, falls nicht vorhanden) const dailyHouseConsumptionWhId = "0_userdata.0.Energie.Senec.Tages_Hausverbrauch_Wh"; // ID des Datenpunkts für den täglichen Hausverbrauch in kWh (wird erstellt, falls nicht vorhanden) const dailyHouseConsumptionKWhId = "0_userdata.0.Energie.Senec.Tages_Hausverbrauch_kWh"; // ====== Konfiguration ENDE ====== // Globale Variablen für die Berechnung let lastPowerValue = 0; // Letzter bekannter Leistungswert let lastUpdateTime = new Date().getTime(); // Zeitpunkt der letzten Aktualisierung in Millisekunden // --- Hilfsfunktionen --- // Funktion zum Erstellen der notwendigen Datenpunkte (States) function createMyStates() { createState(dailyHouseConsumptionWhId, 0, { name: 'Täglicher Hausverbrauch (Wh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'Wh', desc: 'Summierter Hausverbrauch für den aktuellen Tag in Wattstunden' }); createState(dailyHouseConsumptionKWhId, 0, { name: 'Täglicher Hausverbrauch (kWh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'kWh', desc: 'Summierter Hausverbrauch für den aktuellen Tag in Kilowattstunden' }); log("Datenpunkte für den Hausverbrauch überprüft/erstellt."); } // Funktion, um den initialen Wert aus dem Datenpunkt zu lesen und zu loggen async function initializeConsumptionValues() { const state = await getStateAsync(dailyHouseConsumptionWhId); if (state && state.val !== null) { log(`Initialer Wert für täglichen Hausverbrauch Wh: ${state.val} Wh`); } else { setState(dailyHouseConsumptionWhId, 0, true); setState(dailyHouseConsumptionKWhId, 0, true); log(`Datenpunkte ${dailyHouseConsumptionWhId} und ${dailyHouseConsumptionKWhId} auf 0 gesetzt.`); } } // --- Hauptlogik --- // 1. Beim Start des Skripts: Datenpunkte erstellen und initialisieren createMyStates(); initializeConsumptionValues(); // 2. Trigger bei Änderung des Hausverbrauchs-Datenpunkts on({ id: currentHouseConsumptionPowerId, change: 'ne' }, async function (obj) { const currentPower = parseFloat(obj.state.val); // Aktueller Leistungswert in Watt // Prüfen, ob der Wert gültig ist if (isNaN(currentPower)) { log(`Ungültiger Leistungswert erhalten: ${obj.state.val}. Berechnung übersprungen.`, 'warn'); return; } const currentTime = new Date().getTime(); // Aktueller Zeitstempel in Millisekunden // Initialisierung von lastPowerValue und lastUpdateTime beim ersten Trigger if (lastPowerValue === 0 && lastUpdateTime === new Date().getTime()) { const powerState = getState(currentHouseConsumptionPowerId); if (powerState && powerState.val !== null) { lastPowerValue = parseFloat(powerState.val); } else { lastPowerValue = 0; // Fallback } lastUpdateTime = currentTime; log("Initialisierung der Leistungswerte beim ersten Trigger."); return; } const timeDiffSeconds = (currentTime - lastUpdateTime) / 1000; // Zeitdifferenz in Sekunden // Falls keine Zeit vergangen ist (z.B. zu schnelle Updates oder gleicher Zeitstempel) if (timeDiffSeconds <= 0) { // log("Zeitdifferenz ist 0 oder negativ, Überspringe Berechnung.", 'debug'); // Kann viele Logs verursachen return; } // Berechnung der Energie: Leistung (W) * Zeit (s) = Wattsekunden (Ws) const energyWs = currentPower * timeDiffSeconds; // Umrechnung von Wattsekunden in Wattstunden (Ws / 3600 = Wh) const energyWh = energyWs / 3600; log(`Aktuelle Leistung: ${currentPower.toFixed(2)} W, Zeitdiff: ${timeDiffSeconds.toFixed(2)} s, Berechnete Energie: ${energyWh.toFixed(2)} Wh`); // Aktuellen summierten Verbrauch von ioBroker lesen und sicherstellen, dass es eine Zahl ist let currentDailyConsumptionWh = parseFloat((await getStateAsync(dailyHouseConsumptionWhId)).val) || 0; // Energie zum Tagesverbrauch addieren currentDailyConsumptionWh += energyWh; // Werte in die Datenpunkte schreiben setState(dailyHouseConsumptionWhId, currentDailyConsumptionWh.toFixed(2), true); // Wh auf 2 Nachkommastellen setState(dailyHouseConsumptionKWhId, (currentDailyConsumptionWh / 1000).toFixed(3), true); // kWh auf 3 Nachkommastellen log(`Hausverbrauch addiert. Neue Summe: ${currentDailyConsumptionWh.toFixed(2)} Wh (${(currentDailyConsumptionWh / 1000).toFixed(3)} kWh)`); // Werte für die nächste Iteration speichern lastPowerValue = currentPower; lastUpdateTime = currentTime; }); // 3. Reset der Tagessummen um Mitternacht schedule('0 0 * * *', async function () { log("Mitternacht erreicht, setze täglichen Hausverbrauch zurück."); setState(dailyHouseConsumptionWhId, 0, true); setState(dailyHouseConsumptionKWhId, 0, true); // Wichtig: lastUpdateTime muss auch zurückgesetzt werden für korrekte delta-t Berechnung am neuen Tag // und lastPowerValue für den ersten Wert des neuen Tages lastUpdateTime = new Date().getTime(); lastPowerValue = parseFloat((await getStateAsync(currentHouseConsumptionPowerId)).val) || 0; // Aktuellen Power-Wert erneut holen log("Täglicher Hausverbrauch wurde zurückgesetzt."); }); // Optional: Info-Log beim Start des Skripts log("Skript zum Überwachen des täglichen Hausverbrauchs gestartet.");
- Akku Be-und Entladung (schreibt die Werte (batIn und batOut) in DP's , einmal Wh und einmal kWh und wird täglich um 00:00 Uhr auf '0' gesetzt)
// ====== Konfiguration START ====== // Datenpunkt-ID, die die aktuelle Leistung in Watt liefert. // Negativ für BatOut, Positiv für BatIn. // Diesen Wert musst du an deine ioBroker-Installation anpassen! const powerStateId = "senec.0.ENERGY.GUI_BAT_DATA_POWER"; // Beispiel: smartmeter.0.0_1_123_456_789.power_total_current // Datenpunkt-ID für die tägliche BatOut in Wh (wird erstellt, falls nicht vorhanden) const dailyBatOutWhStateId = "0_userdata.0.Energie.Senec.Bat_Out_Wh"; // Datenpunkt-ID für die tägliche BatOut in kWh const dailyBatOutKWhStateId = "0_userdata.0.Energie.Senec.Bat_Out_kWh"; // Datenpunkt-ID für den täglichen BatIn in Wh (wird erstellt, falls nicht vorhanden) const dailyBatInWhStateId = "0_userdata.0.Energie.Senec.Bat_In_Wh"; // Datenpunkt-ID für den täglichen BatIn in kWh const dailyBatInKWhStateId = "0_userdata.0.Energie.Senec.Bat_In_kWh"; // ====== Konfiguration ENDE ====== // Globale Variablen für die Berechnung der Tagessummen let lastPowerValue = 0; // Letzter bekannter Leistungswert let lastUpdateTime = new Date().getTime(); // Zeitpunkt der letzten Aktualisierung in Millisekunden // Funktion zum Initialisieren der Datenpunkte (falls nicht vorhanden) function createStates() { createState(dailyBatOutWhStateId, 0, { name: 'Daily BatOut (Wh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'Wh' }); createState(dailyBatOutKWhStateId, 0, { name: 'Daily BatOut (kWh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'kWh' }); createState(dailyBatInWhStateId, 0, { name: 'Daily BatIn (Wh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'Wh' }); createState(dailyBatInKWhStateId, 0, { name: 'Daily BatIn (kWh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'kWh' }); } // Beim Start des Skripts Datenpunkte erstellen und initialisieren createStates(); // Werte aus den Datenpunkten beim Skriptstart lesen, falls schon vorhanden // Prüfen, ob die Datenpunkte bereits einen Wert haben, ansonsten auf 0 setzen let initialBatOutState = getState(dailyBatOutWhStateId); if (initialBatOutState && initialBatOutState.val !== null) { log(`Initialer Wert für BatOut Wh: ${initialBatOutState.val}`); } else { setState(dailyBatOutWhStateId, 0); log(`Datenpunkt ${dailyBatOutWhStateId} auf 0 gesetzt.`); } let initialBatInState = getState(dailyBatInWhStateId); if (initialBatInState && initialBatInState.val !== null) { log(`Initialer Wert für BatIn Wh: ${initialBatInState.val}`); } else { setState(dailyBatInWhStateId, 0); log(`Datenpunkt ${dailyBatInWhStateId} auf 0 gesetzt.`); } // Trigger bei Änderung des Leistungsdatenpunkts on({ id: powerStateId, change: 'ne' }, async function (obj) { const currentPower = obj.state.val; // Aktueller Leistungswert in Watt const currentTime = new Date().getTime(); // Aktueller Zeitstempel in Millisekunden // Wenn der Wert zum ersten Mal kommt oder Zeitunterschied zu gering ist if (lastPowerValue === 0 && lastUpdateTime === new Date().getTime()) { // Initialisierung lastPowerValue = currentPower; lastUpdateTime = currentTime; log("Initialisierung der Leistungswerte."); return; } const timeDiffSeconds = (currentTime - lastUpdateTime) / 1000; // Zeitdifferenz in Sekunden if (timeDiffSeconds <= 0) { // Falls keine Zeit vergangen ist (z.B. zu schnelle Updates) log("Zeitdifferenz ist 0 oder negativ, Überspringe Berechnung."); return; } // Leistung * Zeit = Energie (Wattsekunden) const energyWs = currentPower * timeDiffSeconds; const energyWh = energyWs / 3600; // Umrechnung von Wattsekunden in Wattstunden log(`Aktuelle Leistung: ${currentPower} W, Zeitdiff: ${timeDiffSeconds.toFixed(2)} s, Berechnete Energie: ${energyWh.toFixed(2)} Wh`); // Sicherstellen, dass die gelesenen Werte Zahlen sind (durch parseFloat oder den Unary-Plus-Operator) let currentBatInWh = parseFloat((await getStateAsync(dailyBatInWhStateId)).val) || 0; let currentBatOutWh = parseFloat((await getStateAsync(dailyBatOutWhStateId)).val) || 0; if (currentPower < 0) { // BatOut currentBatOutWh += Math.abs(energyWh); // Absolutwert, damit die Summe positiv ist setState(dailyBatOutWhStateId, currentBatOutWh.toFixed(2), true); setState(dailyBatOutKWhStateId, (currentBatOutWh / 1000).toFixed(3), true); log(`BatOut addiert. Neue Summe: ${currentBatOutWh.toFixed(2)} Wh`); } else { // BatIn currentBatInWh += energyWh; setState(dailyBatInWhStateId, currentBatInWh.toFixed(2), true); setState(dailyBatInKWhStateId, (currentBatInWh / 1000).toFixed(3), true); log(`BatIn addiert. Neue Summe: ${currentBatInWh.toFixed(2)} Wh`); } // Werte für die nächste Iteration speichern lastPowerValue = currentPower; lastUpdateTime = currentTime; }); // Reset der Tagessummen um Mitternacht schedule('0 0 * * *', async function () { log("Mitternacht erreicht, setze Tagessummen zurück."); setState(dailyBatOutWhStateId, 0, true); setState(dailyBatOutKWhStateId, 0, true); setState(dailyBatInWhStateId, 0, true); setState(dailyBatInKWhStateId, 0, true); // lastUpdateTime muss auch zurückgesetzt werden, um korrekte delta-t Berechnung am neuen Tag zu gewährleisten lastUpdateTime = new Date().getTime(); lastPowerValue = (await getStateAsync(powerStateId)).val || 0; // Aktuellen Power-Wert erneut holen log("Tagessummen wurden zurückgesetzt."); }); // Optional: Für Debugging, wenn das Skript startet log("Skript zum Überwachen von BatOut und BatIn gestartet.");
- Grid Power (schreibt die Werte in DP's (Einspeisung und Netzbezug), einmal Wh und einmal kWh und wird täglich um 00:00 Uhr auf '0' gesetzt)
// ====== Konfiguration START ====== // Datenpunkt-ID, die die aktuelle Leistung in Watt liefert. // Negativ für Einspeisung, Positiv für Netzbezug. // Diesen Wert musst du an deine ioBroker-Installation anpassen! const powerStateId = "senec.0.ENERGY.GUI_GRID_POW"; // Beispiel: smartmeter.0.0_1_123_456_789.power_total_current // Datenpunkt-ID für die tägliche Einspeisung in Wh (wird erstellt, falls nicht vorhanden) const dailyFeedInWhStateId = "0_userdata.0.Energie.Senec.Tages_Einspeisung_Wh"; // Datenpunkt-ID für die tägliche Einspeisung in kWh const dailyFeedInKWhStateId = "0_userdata.0.Energie.Senec.Tages_Einspeisung_kWh"; // Datenpunkt-ID für den täglichen Netzbezug in Wh (wird erstellt, falls nicht vorhanden) const dailyGridPurchaseWhStateId = "0_userdata.0.Energie.Senec.Tages_Netzbezug_Wh"; // Datenpunkt-ID für den täglichen Netzbezug in kWh const dailyGridPurchaseKWhStateId = "0_userdata.0.Energie.Senec.Tages_Netzbezug_kWh"; // ====== Konfiguration ENDE ====== // Globale Variablen für die Berechnung der Tagessummen let lastPowerValue = 0; // Letzter bekannter Leistungswert let lastUpdateTime = new Date().getTime(); // Zeitpunkt der letzten Aktualisierung in Millisekunden // Funktion zum Initialisieren der Datenpunkte (falls nicht vorhanden) function createStates() { createState(dailyFeedInWhStateId, 0, { name: 'Tägliche Einspeisung (Wh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'Wh' }); createState(dailyFeedInKWhStateId, 0, { name: 'Tägliche Einspeisung (kWh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'kWh' }); createState(dailyGridPurchaseWhStateId, 0, { name: 'Täglicher Netzbezug (Wh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'Wh' }); createState(dailyGridPurchaseKWhStateId, 0, { name: 'Täglicher Netzbezug (kWh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'kWh' }); } // Beim Start des Skripts Datenpunkte erstellen und initialisieren createStates(); // Werte aus den Datenpunkten beim Skriptstart lesen, falls schon vorhanden // Prüfen, ob die Datenpunkte bereits einen Wert haben, ansonsten auf 0 setzen let initialFeedInState = getState(dailyFeedInWhStateId); if (initialFeedInState && initialFeedInState.val !== null) { log(`Initialer Wert für Einspeisung Wh: ${initialFeedInState.val}`); } else { setState(dailyFeedInWhStateId, 0); log(`Datenpunkt ${dailyFeedInWhStateId} auf 0 gesetzt.`); } let initialGridPurchaseState = getState(dailyGridPurchaseWhStateId); if (initialGridPurchaseState && initialGridPurchaseState.val !== null) { log(`Initialer Wert für Netzbezug Wh: ${initialGridPurchaseState.val}`); } else { setState(dailyGridPurchaseWhStateId, 0); log(`Datenpunkt ${dailyGridPurchaseWhStateId} auf 0 gesetzt.`); } // Trigger bei Änderung des Leistungsdatenpunkts on({ id: powerStateId, change: 'ne' }, async function (obj) { const currentPower = obj.state.val; // Aktueller Leistungswert in Watt const currentTime = new Date().getTime(); // Aktueller Zeitstempel in Millisekunden // Wenn der Wert zum ersten Mal kommt oder Zeitunterschied zu gering ist // Hier ist es wichtig, dass lastPowerValue und lastUpdateTime initialisiert werden if (lastPowerValue === 0 && lastUpdateTime === new Date().getTime()) { // Initialisierung const powerState = getState(powerStateId); if (powerState && powerState.val !== null) { lastPowerValue = powerState.val; } else { lastPowerValue = 0; // Fallback, falls kein Wert verfügbar } lastUpdateTime = currentTime; log("Initialisierung der Leistungswerte beim ersten Trigger."); return; } const timeDiffSeconds = (currentTime - lastUpdateTime) / 1000; // Zeitdifferenz in Sekunden if (timeDiffSeconds <= 0) { // Falls keine Zeit vergangen ist (z.B. zu schnelle Updates) log("Zeitdifferenz ist 0 oder negativ, Überspringe Berechnung."); return; } // Leistung * Zeit = Energie (Wattsekunden) const energyWs = currentPower * timeDiffSeconds; const energyWh = energyWs / 3600; // Umrechnung von Wattsekunden in Wattstunden log(`Aktuelle Leistung: ${currentPower} W, Zeitdiff: ${timeDiffSeconds.toFixed(2)} s, Berechnete Energie: ${energyWh.toFixed(2)} Wh`); // **KORRIGIERTER BEREICH START** // Sicherstellen, dass die gelesenen Werte Zahlen sind (durch parseFloat oder den Unary-Plus-Operator) let currentFeedInWh = parseFloat((await getStateAsync(dailyFeedInWhStateId)).val) || 0; let currentGridPurchaseWh = parseFloat((await getStateAsync(dailyGridPurchaseWhStateId)).val) || 0; // **KORRIGIERTER BEREICH ENDE** if (currentPower < 0) { // Einspeisung currentFeedInWh += Math.abs(energyWh); // Absolutwert, damit die Summe positiv ist setState(dailyFeedInWhStateId, currentFeedInWh.toFixed(2), true); setState(dailyFeedInKWhStateId, (currentFeedInWh / 1000).toFixed(3), true); log(`Einspeisung addiert. Neue Summe: ${currentFeedInWh.toFixed(2)} Wh`); } else { // Netzbezug currentGridPurchaseWh += energyWh; setState(dailyGridPurchaseWhStateId, currentGridPurchaseWh.toFixed(2), true); setState(dailyGridPurchaseKWhStateId, (currentGridPurchaseWh / 1000).toFixed(3), true); log(`Netzbezug addiert. Neue Summe: ${currentGridPurchaseWh.toFixed(2)} Wh`); } // Werte für die nächste Iteration speichern lastPowerValue = currentPower; lastUpdateTime = currentTime; }); // Reset der Tagessummen um Mitternacht schedule('0 0 * * *', async function () { log("Mitternacht erreicht, setze Tagessummen zurück."); setState(dailyFeedInWhStateId, 0, true); setState(dailyFeedInKWhStateId, 0, true); setState(dailyGridPurchaseWhStateId, 0, true); setState(dailyGridPurchaseKWhStateId, 0, true); // lastUpdateTime muss auch zurückgesetzt werden, um korrekte delta-t Berechnung am neuen Tag zu gewährleisten lastUpdateTime = new Date().getTime(); lastPowerValue = (await getStateAsync(powerStateId)).val || 0; // Aktuellen Power-Wert erneut holen log("Tagessummen wurden zurückgesetzt."); }); // Optional: Für Debugging, wenn das Skript startet log("Skript zum Überwachen von Einspeisung und Netzbezug gestartet.");
wer Lust hat kann ja mit testen ob das so passt.
-
Hallo
Sieht gut aus bis jetzt. Ist es möglich, für diese Datenpunkte jährliche Datenpunkte zu integrieren?Viele Grüße
Semmy