simatec / ioBroker.solax

solax adapter for ioBroker
MIT License
17 stars 8 forks source link

falscher Wert bei Datenpunkt "yieldtotal" / Solax X3 Hybrid G4 #202

Closed 6smile9 closed 2 weeks ago

6smile9 commented 7 months ago

Hallo zusammen,

ich habe beim Solax-Adapter folgenden Fehler entdeckt: Bei Wechselrichter: Solax X3 Hybrid G4 wird, bei Verwendung über IP des lokalen WiFi-Pocket-Stick 3.0, der Datenpunkt „yieldtotal“ nicht richtig ausgelesen und zeigt einen falschen Wert an. Angezeigter Wert: 5062,3 Soll-Wert (gem. API): 11615,6

Neustart und Neuinstallation des Adapters brachten keine Besserung.

Version Solax-Adapter: 0.9.6 ioBroker läuft auf Proxmox, Node.js v18.19.0, NPM 10.2.3

Danke und Gruß

thorsten-vogt commented 6 months ago

Hallo @6smile9,

Du musst den Wert im iobroker selbst berechnen.

Ich habe bei mir im iobroker einen Datenpunkt "0_userdata.0.solax.0.RealTotalYield" angelegt und folgende Berechnung in einem Skript durchgeführt: 0_userdata.0.solax.0.RealTotalYield = solax.0.data.yieldtotalOverflow' * 6553.5 + solax.0.data.yieldtotal

folgendes Skript zum anlegen des Datenpunktes 1x ausgeführt: createState('0_userdata.0.solax.0.RealTotalYield', {name: 'solax.0.RealTotalYield', type: 'number', role: 'value.power', unit: 'kWh', read: true, write: true });

und folgendes Skript dauerhaft in Ausführung: // RealTotalYield on({ id: 'solax.0.data.yieldtotal' , change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.RealTotalYield' /* Gesamt-yield */, (parseFloat(getState('solax.0.data.yieldtotalOverflow').val) * 6553.5 + parseFloat(getState('solax.0.data.yieldtotal').val)), true); });

Das muss dann mit allen Werten gemacht werden, für die es Overflow-Werte gibt: createState('0_userdata.0.solax.0.RealTotalYield', {name: 'solax.0.RealTotalYield', type: 'number', role: 'value.power', unit: 'kWh', read: true, write: true }); createState('0_userdata.0.solax.0.RealTotalConsumption', {name: 'solax.0.RealTotalConsumption', type: 'number', role: 'value.power', unit: 'kWh', read: true, write: true }); createState('0_userdata.0.solax.0.RealTotalFeedIn', {name: 'solax.0.RealTotalFeedIn', type: 'number', role: 'value.power', unit: 'kWh', read: true, write: true }); createState('0_userdata.0.solax.0.RealTotalBatteryChargeFromGrid', {name: 'solax.0.RealTotalBatteryChargeFromGrid', type: 'number', role: 'value.power', unit: 'kWh', read: true, write: true }); createState('0_userdata.0.solax.0.RealTotalBatteryDischargeEnergy', {name: 'solax.0.RealTotalBatteryDischargeEnergy', type: 'number', role: 'value.power', unit: 'kWh', read: true, write: true }); createState('0_userdata.0.solax.0.RealTotalBatteryChargeEnergy', {name: 'solax.0.RealTotalBatteryChargeEnergy', type: 'number', role: 'value.power', unit: 'kWh', read: true, write: true }); createState('0_userdata.0.solax.0.RealTotalPVEnergy', {name: 'solax.0.RealTotalPVEnergy', type: 'number', role: 'value.power', unit: 'kWh', read: true, write: true }); //Calculated Values createState('0_userdata.0.solax.0.RealTotalSelfUse', {name: 'solax.0.RealTotalSelfUse', type: 'number', role: 'value.power', unit: 'kWh', read: true, write: true }); createState('0_userdata.0.solax.0.TotalSelfUseInPercent', {name: 'solax.0.TotalSelfUseInPercent', type: 'number', role: 'value', unit: '%', read: true, write: true }); createState('0_userdata.0.solax.0.AutarkyInPercent', {name: 'solax.0.AutarkyInPercent', type: 'number', role: 'value', unit: '%', read: true, write: true }); createState('0_userdata.0.solax.0.InverterEffectivity', {name: 'solax.0.InverterEffectivity', type: 'number', role: 'value', unit: '%', read: true, write: true }); createState('0_userdata.0.solax.0.BatteryEffectivity', {name: 'solax.0.BatteryEffectivity', type: 'number', role: 'value', unit: '%', read: true, write: true });

und: `// RealTotalYield on({ id: 'solax.0.data.yieldtotal' , change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.RealTotalYield' / Gesamt-yield /, (parseFloat(getState('solax.0.data.yieldtotalOverflow').val) 6553.5 + parseFloat(getState('solax.0.data.yieldtotal').val)), true); }); // RealTotalPVEnergy on({ id: 'solax.0.data.totalpvenergy', change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.RealTotalPVEnergy' / Gesamt-PV /, (parseFloat(getState('solax.0.data.totalpvenergyOverflow').val) 6553.5 + parseFloat(getState('solax.0.data.totalpvenergy').val)), true); }); // RealTotalConsumption on({ id: 'solax.0.data.totalconsumption', change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.RealTotalConsumption', (parseFloat(getState('solax.0.data.totalConsumptionOverflow').val) 655.35 + parseFloat(getState('solax.0.data.totalconsumption').val)), true); }); // RealTotalFeedIn on({ id: 'solax.0.data.totalFeed', change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.RealTotalFeedIn', (parseFloat(getState('solax.0.data.totalFeedOverflow').val) 655.35 + parseFloat(getState('solax.0.data.totalFeed').val)), true); }); // RealTotalBatteryChargeEnergy on({ id: 'solax.0.data.totalBatteryChargeEnergy', change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.RealTotalBatteryChargeEnergy', (parseFloat(getState('solax.0.data.totalBatteryChargeEnergyOverflow').val) 6553.5 + parseFloat(getState('solax.0.data.totalBatteryChargeEnergy').val)), true); }); // RealTotalBatteryDischargeEnergy on({ id: 'solax.0.data.totalBatteryDischargeEnergy', change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.RealTotalBatteryDischargeEnergy', (parseFloat(getState('solax.0.data.totalBatteryDischargeEnergyOverflow').val) 6553.5 + parseFloat(getState('solax.0.data.totalBatteryDischargeEnergy').val)), true); }); // RealTotalBatteryChargeFromGrid on({ id: 'solax.0.data.totalBatteryInputFromGrid', change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.RealTotalBatteryChargeFromGrid', (parseFloat(getState('solax.0.data.totalBatteryInputFromGridOverflow').val) * 6553.5 + parseFloat(getState('solax.0.data.totalBatteryInputFromGrid').val)), true); });

/****

// RealTotalSelfUse on({ id: '0_userdata.0.solax.0.RealTotalYield' , change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.RealTotalSelfUse', (parseFloat(getState('0_userdata.0.solax.0.RealTotalYield').val) - parseFloat(getState('0_userdata.0.solax.0.RealTotalFeedIn').val)), true); }); // TotalSelfUseInPercent on({ id: '0_userdata.0.solax.0.RealTotalYield' , change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.TotalSelfUseInPercent', (parseFloat(getState('0_userdata.0.solax.0.RealTotalSelfUse').val) / parseFloat(getState('0_userdata.0.solax.0.RealTotalYield').val) 100), true); }); // AutarkyInPercent on({ id: '0_userdata.0.solax.0.RealTotalYield' , change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.AutarkyInPercent', (parseFloat(getState('0_userdata.0.solax.0.RealTotalSelfUse').val) / (parseFloat(getState('0_userdata.0.solax.0.RealTotalConsumption').val) + parseFloat(getState('0_userdata.0.solax.0.RealTotalSelfUse').val)) 100), true); });

// Inverter Effektivität on({ id: '0_userdata.0.solax.0.RealTotalYield' , change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.InverterEffectivity', (parseFloat(getState('0_userdata.0.solax.0.RealTotalYield').val) / parseFloat(getState('0_userdata.0.solax.0.RealTotalPVEnergy').val) 100), true); }); // BatteryEffectivity on({ id: '0_userdata.0.solax.0.RealTotalBatteryDischargeEnergy' , change: 'ne' }, async (obj) => { let value = obj.state.val; let oldValue = obj.oldState.val; setState('0_userdata.0.solax.0.BatteryEffectivity', (parseFloat(getState('0_userdata.0.solax.0.RealTotalBatteryDischargeEnergy').val) / parseFloat(getState('0_userdata.0.solax.0.RealTotalBatteryChargeEnergy').val) 100), true); });`

Ich hoffe das hilft weiter!

6smile9 commented 6 months ago

Hallo @thorsten-vogt,

erstmal vielen Dank für die vielen (neuen) Infos.

Ich bin noch relativ neu in der ioBroker-Welt und sehr interessiert ständig etwas hinzu zu lernen.

Ich hätte zu Deinen o. a. Infos noch folgenden Fragen:

  1. woher bekommt man denn solche Informationen? Ich habe in der Dokumentation des Adapters nichts darüber gefunden.
  2. welche Bedeutung haben diese "Overflow-Datenpunkte" und was hat es mit dem Wert 6553,5 auf sich?
  3. sind das deine aktuellen Skript-Daten? Habe gesehen, dass bei RealTotalConsumption und RealTotalFeedIn nicht mit 6553,5 multipliziert wird, sondern mit 655,35 Ist das so korrekt?

Danke und Gruß

thorsten-vogt commented 6 months ago

Hallo @6smile9,

ich habe vor einigen Monaten das gleiche Phänomen wie Du beobachtet (vgl. [https://github.com/simatec/ioBroker.solax/issues/189] ). Simatec hat dann mit der Version 0.9.3 die Überlaufcounter hinzugefügt. Das mit dem Überlauf kommt noch aus der "alten" IT-Zeit. Intern verarbeitet der Wechselrichter die Daten mit 16 Bit. 16 Bit als ganzzahliger positiver Wert ist 65535 oder auch mathematisch 2^16-1 (Zwei hoch 16 und davon 1 abziehen). Einige Werte werden mit einer höheren Genauigkeit dargestellt, diese werden dann mit 655,35 multipliziert, haben also zwei Nachkommastellen und laufen entsprechend häufiger über. Andere Werte haben nur eine geringere Genauigkeit (eine Nachkommastelle) mit 6553,5 und laufen weniger häufig über. Da es von Solax keine Dokumentation zum auslesen über die lokale REST-Schnittstelle gibt müssen wir versuchen simatec bei der Analyse zu helfen, speziell, da er ja nicht alle Wechselrichter-Modelle zur Verfügung hat. Und ja, das sind meine Skript-Daten. Gerne kannst Du damit testen. Bei mir sehen die Daten so plausibel aus. Wenn das bei dir auch passt dann kann simatec das ggf. in einer zukünftigen Version einbauen.

Ich hoffe das konnte das etwas erklären.

Gruß

Charlie-2222 commented 3 months ago

Hallo, Ich habe einen „X1-Boost/Air/Mini“ und mein Adapter hat auch plötzlich wieder bei null angefangen nachdem er in den 65536 Wertebereich gekommen ist. Allerdings konnte ich kein „Überlauf“ bei meinen Solax Objekten (neuste Beta) finden - oder an welcher Stelle ist das bei den JSON Daten zu finden ?

Charlie-2222 commented 2 weeks ago

Auf der einen Seite bin ich dankbar, dass ich diesen Adapter kostenfrei nutzen kann, Dennoch wäre eine kurze Antwort vom Entwickler auf meine Frage sehr nett gewesen, bevor das Ticket geschlossen wurde.

simatec commented 2 weeks ago

Ich hatte es doch im Issue schon mehrfach geschrieben. Liefert bitte die richtigen Werte und es kann eingebaut werden. ich selber habe nicht alle WR zur Verfügung. und dein Post sagt leider nichts aus, außer das irgendein Wert auf null gesprungen ist. Weder sagst du welcher State auf null ist oder der Gleichen. Wie soll man damit etwas anfangen?

Charlie-2222 commented 1 week ago

Vieleicht hatte ich hier zu viele Informationen vorausgestezt ... Ich wollte mich eigentlich nur an dieses Thema anhängen, da ich genau das gleich Problem mit "yieldtotal" habe.

Ich habe einen "Solax X1-Boost/Air/Mini" mit dem ioB Adapter im expert mode am laufen. Die Frage war hier, ob der Überlauf im Rückgabe String zu finden ist, oder ob er mittels ioBroker Sript selbst erkannt werden muss.

Anbrei der Rückgabe String für : curl -d "optType=ReadRealTimeData&pwd=xxxxxxx" -X POST http://192.168.xx.xxx

{"sn":"xxxxxxxx","ver":"3.008.10","type":4,"Data":[2369,64,1409,1984,3344,24,29,478,976,4999,2,26059,1,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,0,8569,0,0,0,0,0,0,0,0,0,0,0,0,0,43,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"Information":[4.200,4,"XB3242I3468134",8,2.29,0.00,1.47,0.00,0.00,1]}

Danke

simatec commented 1 week ago

Wie ich oben schon geschrieben habe, den Wert für den Überlauf musst du selber ermitteln, da ich nicht alle WR zum testen habe. Ermittle in der json die Position des Wertes und die poste hier die Umrechnung... dann baue ich es ein.

Das auszählen in der json beginnt mit 0 (also in deinem Beispiel ist der Wert 2369 die Position 0)