NEWS
Hoymiles WR mit 1600W regeln
-
Guten Abend miteinander,
ich habe folgendes Setup:
mME --> Einspeisung WR auf L1 --> ShellyEM 3 --> Verbraucher
Dieser Aufbau ist den Gegebenheiten geschuldet.
Ich schreibe meine Daten mittels des Shelly-Adapter in iobroker und mqtt mit. Die Daten des WR liefert mir eine OpenDTU - diese soll auch die neue Leistungsgrenze schreiben.
Ich habe folgenden JavaScript-Code erarbeitet:
// Datenpunkte const wrPowerDP = 'opendtu.0.1164a00f8949.ac.phase_1.power'; // Wechselrichter-Leistung const housePowerDP = 'shelly.0.SHEM-3#485519C98888#1.Total.InstantPower'; // Hausverbrauch const mqttLimitDP = 'opendtu.0.1164a00f8949.power_control.limit_nonpersistent_absolute'; // MQTT Limit-Datenpunkt const producingDP = 'opendtu.0.1164a00f8949.producing'; // Producing Status // Konfiguration const thresholdWR = 800; // Mindestleistung des Wechselrichters in Watt const thresholdDifferenceMin = 400; // Mindestdifferenz für das Setzen eines Limits const thresholdDifferenceMax = 50; // Maximale Differenz, um das Limit zu erhöhen const maxWRPower = 1600; // Maximale zulässige Leistung des WR const changeThreshold = 10; // Schwellenwert für signifikante Limitänderung (in Watt) // Initialisiere Zähler-Datenpunkte für Prüfungen und Limitänderungen if (!existsState('0_userdata.0.solar.check_counter')) { createState('0_userdata.0.solar.check_counter', 0, { name: 'Anzahl der Prüfungen', type: 'number', unit: 'Prüfungen', read: true, write: true }); } if (!existsState('0_userdata.0.solar.change_counter')) { createState('0_userdata.0.solar.change_counter', 0, { name: 'Anzahl der Prüfungen mit Limitänderung', type: 'number', unit: 'Prüfungen', read: true, write: true }); } if (!existsState('0_userdata.0.solar.no_change_counter')) { createState('0_userdata.0.solar.no_change_counter', 0, { name: 'Anzahl der Prüfungen ohne Limitänderung', type: 'number', unit: 'Prüfungen', read: true, write: true }); } // Differenz-Datenpunkt für Grafana if (!existsState('0_userdata.0.solar.wr_haus_difference')) { createState('0_userdata.0.solar.wr_haus_difference', 0, { name: 'WR - Haus Leistung Differenz', type: 'number', unit: 'Watt', read: true, write: true }); } // Zustand für Low Power Mode if (!existsState('0_userdata.0.solar.low_power_mode')) { createState('0_userdata.0.solar.low_power_mode', false, { name: 'Low Power Mode aktiv', type: 'boolean', read: true, write: true }); } // Funktion zur Berechnung des Limits function calculateLimit(wrPower, housePower) { let limit = wrPower - thresholdDifferenceMin; if (wrPower - housePower < thresholdDifferenceMax || wrPower - housePower > thresholdDifferenceMin) { limit = housePower + thresholdDifferenceMin; } if (limit < 0) { limit = 0; } else if (limit > maxWRPower) { limit = maxWRPower; } return limit; } // Hauptfunktion zur Leistungsprüfung und Limitsteuerung function checkPower() { const wrPower = getState(wrPowerDP).val; const housePower = getState(housePowerDP).val; const powerDifference = parseFloat((wrPower - housePower).toFixed(2)); const isLowPower = getState('0_userdata.0.solar.low_power_mode').val; const currentLimit = getState(mqttLimitDP).val; // Prüfungszähler erhöhen let checkCount = getState('0_userdata.0.solar.check_counter').val + 1; setState('0_userdata.0.solar.check_counter', checkCount); // WR-Leistung unter Schwellwert → Low Power Mode if (wrPower < thresholdWR) { if (!isLowPower) { console.log('WR-Leistung unter ' + thresholdWR + ' W – Low Power Mode aktiviert'); console.log('Limit wird geändert von ' + currentLimit + ' W auf ' + maxWRPower + ' W'); setState(mqttLimitDP, maxWRPower); setState('0_userdata.0.solar.low_power_mode', true); let changeCount = getState('0_userdata.0.solar.change_counter').val + 1; setState('0_userdata.0.solar.change_counter', changeCount); } else { console.log('Low Power Mode aktiv – WR-Leistung weiter unter ' + thresholdWR + ' W'); console.log('Limit bleibt unverändert bei ' + currentLimit + ' W'); let noChangeCount = getState('0_userdata.0.solar.no_change_counter').val + 1; setState('0_userdata.0.solar.no_change_counter', noChangeCount); } } else { if (isLowPower) { console.log('WR-Leistung über ' + thresholdWR + ' W – Low Power Mode deaktiviert'); setState('0_userdata.0.solar.low_power_mode', false); } if (powerDifference >= 0) { const newLimit = calculateLimit(wrPower, housePower); if (Math.abs(currentLimit - newLimit) >= changeThreshold) { console.log('Limit wird geändert von ' + currentLimit + ' W auf ' + newLimit + ' W'); setState(mqttLimitDP, newLimit); let changeCount = getState('0_userdata.0.solar.change_counter').val + 1; setState('0_userdata.0.solar.change_counter', changeCount); } else { console.log('Limit bleibt unverändert bei ' + currentLimit + ' W – Änderung (' + Math.abs(currentLimit - newLimit) + ' W) unterhalb Schwelle (' + changeThreshold + ' W)'); let noChangeCount = getState('0_userdata.0.solar.no_change_counter').val + 1; setState('0_userdata.0.solar.no_change_counter', noChangeCount); } } else { console.log('Keine Regelung – WR-Haus Differenz negativ (' + powerDifference + ' W)'); } } setState('0_userdata.0.solar.wr_haus_difference', powerDifference); } // Sofort prüfen bei Produktionsstart on({ id: producingDP, val: true }, function () { console.log('Produktion gestartet – Starte erste Prüfung der Leistung'); checkPower(); }); // Zyklische Prüfung alle 15 Sekunden bei aktiver Produktion setInterval(function () { if (getState(producingDP).val === true) { checkPower(); } }, 60000);Ich möchte die Anzahl der Schreibvorgänge auf den WR so gering wie möglich halten, daher die eingebauten Einschränkungen.
Allerdings klappt das schreiben des neuen Limit auf den WR nicht - habe ich irgendwo einen Denkfehler?
Gruß, NobbyNobs
-
Die Logik in "calculateLimit()" ist für mich unklar.
if (wrPower - housePower < thresholdDifferenceMax || wrPower - housePower > thresholdDifferenceMin)Diese Bedingung ist irgendwie logisch nicht richtig, glaube ich. Sie trifft immer zu, wenn powerDifference außerhalb des Bereichs thresholdDifferenceMax bis thresholdDifferenceMin liegt.
Versuche das mal.
// =========================== // Konfiguration // =========================== const wrPowerDP = 'opendtu.0.1164a00f8949.ac.phase_1.power'; const housePowerDP = 'shelly.0.SHEM-3#485519C98888#1.Total.InstantPower'; const mqttLimitDP = 'opendtu.0.1164a00f8949.power_control.limit_nonpersistent_absolute'; const producingDP = 'opendtu.0.1164a00f8949.producing'; const thresholdWR = 800; const thresholdDifferenceMin = 400; const thresholdDifferenceMax = 50; const maxWRPower = 1600; const changeThreshold = 10; const debug = true; // Setze auf false, um Logs zu deaktivieren // =========================== // Datenpunkt-Initialisierung // =========================== const statesToInit = [ { id: '0_userdata.0.solar.check_counter', default: 0, name: 'Anzahl der Prüfungen', type: 'number', unit: 'Prüfungen' }, { id: '0_userdata.0.solar.change_counter', default: 0, name: 'Anzahl der Prüfungen mit Limitänderung', type: 'number', unit: 'Prüfungen' }, { id: '0_userdata.0.solar.no_change_counter', default: 0, name: 'Anzahl der Prüfungen ohne Limitänderung', type: 'number', unit: 'Prüfungen' }, { id: '0_userdata.0.solar.wr_haus_difference', default: 0, name: 'WR - Haus Leistung Differenz', type: 'number', unit: 'Watt' }, { id: '0_userdata.0.solar.low_power_mode', default: false, name: 'Low Power Mode aktiv', type: 'boolean' } ]; statesToInit.forEach(dp => { if (!existsState(dp.id)) { createState(dp.id, dp.default, { name: dp.name, type: dp.type, unit: dp.unit, read: true, write: true }); } }); // =========================== // Limitberechnung // =========================== function calculateLimit(wrPower, housePower) { let powerDiff = wrPower - housePower; let limit; if (powerDiff >= thresholdDifferenceMax && powerDiff <= thresholdDifferenceMin) { limit = housePower + thresholdDifferenceMin; } else { limit = wrPower - thresholdDifferenceMin; } if (limit < 0) limit = 0; else if (limit > maxWRPower) limit = maxWRPower; return limit; } // =========================== // Hauptfunktion // =========================== function checkPower() { const wrPower = getState(wrPowerDP)?.val ?? 0; const housePower = getState(housePowerDP)?.val ?? 0; const powerDifference = parseFloat((wrPower - housePower).toFixed(2)); const isLowPower = getState('0_userdata.0.solar.low_power_mode')?.val ?? false; const currentLimit = getState(mqttLimitDP)?.val ?? 0; // Prüfungszähler erhöhen let checkCount = getState('0_userdata.0.solar.check_counter')?.val ?? 0; setState('0_userdata.0.solar.check_counter', ++checkCount); if (wrPower < thresholdWR) { if (!isLowPower) { if (debug) { console.log(`WR-Leistung unter ${thresholdWR} W – Low Power Mode aktiviert`); console.log(`Limit wird geändert von ${currentLimit} W auf ${maxWRPower} W`); } setState(mqttLimitDP, maxWRPower); setState('0_userdata.0.solar.low_power_mode', true); let changeCount = getState('0_userdata.0.solar.change_counter')?.val ?? 0; setState('0_userdata.0.solar.change_counter', ++changeCount); } else { if (debug) { console.log(`Low Power Mode aktiv – WR-Leistung weiter unter ${thresholdWR} W`); console.log(`Limit bleibt unverändert bei ${currentLimit} W`); } let noChangeCount = getState('0_userdata.0.solar.no_change_counter')?.val ?? 0; setState('0_userdata.0.solar.no_change_counter', ++noChangeCount); } } else { if (isLowPower) { if (debug) console.log(`WR-Leistung über ${thresholdWR} W – Low Power Mode deaktiviert`); setState('0_userdata.0.solar.low_power_mode', false); } if (powerDifference >= 0) { const newLimit = calculateLimit(wrPower, housePower); const diff = Math.abs(currentLimit - newLimit); if (diff >= changeThreshold) { if (debug) console.log(`Limit wird geändert von ${currentLimit} W auf ${newLimit} W`); setState(mqttLimitDP, newLimit); let changeCount = getState('0_userdata.0.solar.change_counter')?.val ?? 0; setState('0_userdata.0.solar.change_counter', ++changeCount); } else { if (debug) console.log(`Limit bleibt unverändert bei ${currentLimit} W – Änderung (${diff} W) unterhalb Schwelle (${changeThreshold} W)`); let noChangeCount = getState('0_userdata.0.solar.no_change_counter')?.val ?? 0; setState('0_userdata.0.solar.no_change_counter', ++noChangeCount); } } else { if (debug) console.log(`Keine Regelung – WR-Haus Differenz negativ (${powerDifference} W)`); } } setState('0_userdata.0.solar.wr_haus_difference', powerDifference); } // =========================== // Event- und Zeitsteuerung // =========================== on({ id: producingDP, val: true }, function () { if (debug) console.log('Produktion gestartet – Starte erste Prüfung der Leistung'); checkPower(); }); // Zyklische Prüfung alle 60 Sekunden setInterval(() => { if (getState(producingDP)?.val === true) { checkPower(); } }, 60000); -
Da du sowieso OPENDTU verwendest, verwende OpenDTU on Battery.
Damit kannst du den Wechselrichter nach aktuellem Strombedarf steuern.
Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.
Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.
Mit deinem Input könnte dieser Beitrag noch besser werden 💗
Registrieren Anmelden