Huawei Sun2000 mit OpenHAB

Aus Debacher-Wiki
Zur Navigation springenZur Suche springen

Huawei stellt für seine Sun2000 eine Reihe von Zugriffsmöglichkeiten zur Verfügung, über die man die Leistungsdaten der Anlage abfragen kann. Ich möchte aber diese Daten auch innerhalb von OpenHAB zur Verfügung haben. Dann kann ich z.B. den Stromertrag mit den Werten meines Helligkeits-Sensors vergleichen. Für meine Ziele ist der Zugriff über Modbus sinnvoller, als der über die Northbound API, ich sehe dafür folgende Vorteile:

  • die Werte sind aktueller, den Modbus kann ich alle 5 sec abfragen, die API liefert nur alle 5 Minuten neue Daten
  • die Solaranlage soll mindestens 20 Jahre laufen, wer weiß, ob die API dann noch gepflegt wird

Das Modbus-Binding

OpenHAB stellt (zumindest bis Version 4.0.2) kein spezielles Binding für die Sun2000 zur Verfügung. Was es aber gibt, ist ein Modbus-Binding. Ein eventuelles Sun2000-Binding würde ja auch die Modbus-Schnittstelle nutzen, es könnte eigentlich nur das Handling vereinfachen.

Bevor man mit der OpenHAB Konfiguration beginnt, sollte man sich z.B. mit Huawei_Sun2000_Daten_abfragen#BOPV.Info vergewissern, dass der Modbus Zugriff funktioniert.

Der Zugriff über das Modbus-Interface erfolgt in mehreren Schritten (Für den Screenshot habe ich das Modbus-Binding installiert und dann unter Things auf Hinzufügen (das blaue Pluszeichen) geklickt und dann das Modbus-Binding durch Klicken ausgewählt):

2023-08-31 14.49.11 192.168.1.119 c4602e704b9d.png

Modbus TCP Slave

Im ersten Schritt wird der Modbus TCP Slave benötigt:

2023-08-31 15.01.16 192.168.1.119 ed730feffc61.png

Dieses Thing ist die Schnittstelle zwischen OpenHAB und der Sun2000. Angeben muss man hier:

  • IP-Adresse des Gerätes
  • den Port, in der Regel 502
  • die id des Gerätes, üblicherweise 1

Den Rest habe ich unverändert gelassen. Der Status muss nach kurzer Zeit auf Online gehen.

Regular Poll

Danach wird (mindestens) ein Regular Poll benötigt. Damit wird eine Gruppe von Registern der Anlage abgefragt. Die Anlage stellt ihre Daten in einer Vielzahl von Registern zur Verfügung. Man kann auf keinen Fall alle Register gleichzeitig einlesen. Außerdem gibt es im Adressbereich der Register immer wieder auch größere Lücken. Daher fragt man immer zusammenhängende Bereiche in kleineren Gruppen ab.

2023-08-31 15.08.45 192.168.1.119 12f948f82def.png

Der Poll nutzt den vorher eingerichteten Modbus TCP Slavee als Bridge. Weiterhin gibt man an, ab welchem Register abgefragt werden soll, hier ab Nummer 32064. Dann noch wieviele zusammenhängende Register abgefragt werden sollen, hier 25. Als Typ ist hier holding register gewählt. Wichtig ist noch die Zeitangabe unter Poll Interval deutlich zu erhöhen. Vorgabe ist 500, was einer halben Sekunde entspricht. Bei mir ist 5000 angegeben, was 5 Sekunden entspricht. Das Dongle, über das die Kommunikation erfolgt, ist bei zu schneller Folge von Abfragen schnell überfordert und die Verbindung kann dann instabil werden. Für Wertebereich, die sich selten oder nie ändern kann man den Wert deutlich höher setzen, um das Dongle zu entlasten.

Da eine Anzahl an solchen Polls zusammen kommt und eine noch größere Anzahl an Modbus Data Things ist aus meiner Sicht eine sinnvolle Benennung wichtig. Um diese ganzen Things einigermaßen übersichtlich zu halten, bin ich bei der Benennung ganz systematisch vorgegangen.

  • Das Label für eine Poll beginnt mit dem Wort Poll,
  • danach kommt das Startregister und durch ein Minuszeichen verbunden die Zahl der Register,
  • zuletzt kommt dann noch eine kurze Beschreibung für die Gruppe, hier Power.

Modbus Data

Was der Poll liefert, sind einfach Speicherinhalte in Form von Zahlen. Wie diese Zahlen zu interpretieren sind muss man der Dokumentation entnehmen. OpenHAB kann nicht erkennen, ob eine Zahl für einen Buchstaben steht oder Teil eines 32 Bit Integer ist. Daher muss man die abgefragten Registerinhalte für OpenHAB noch quasi interpretieren.

Dazu dient ein Modbus Data Thing.

2023-08-31 15.36.14 192.168.1.119 ab4a52f79125.png

Das Data Thing benutzt den vorher definierten Poll als Bridge. Dann braucht es eine Reihe von Informationen. Zuerst einmal die Register-Nummer von der das Daum stammt, hier wieder 32064 (oder ein anderes Register aus dem Poll). Dann kann man die gelesenen Daten transformieren. Die Sun2000 arbeitet immer mit Integer-Zahlen unterschiedlicher Längen. Die Nachkommastellen werden also durch Multiplikation mit Zehnerpotenzen in den ganzzahligen Bereich geschoben. Dies kann man hier rückgängig machen und damit wieder Zahlen mit Nachkommastellen erzeugen. Im vorliegenden Fall werden drei Nachkommastellen im Ergebnis realisiert. Dann muss man OpenHAB vermitteln, was für ein Zahlenbereich vorliegt. Im Beispiel 32bit signed integer, also eine 4 Byte große Zahl mit Vorzeichen. Um den unteren Teil der Angaben habe ich mich nicht gekümmert, weil ich nur lesen möchte und nicht schreiben.

Bei der Benennung der Elemente bin ich ähnlich wie beim Poll vorgegangen

  • am Anfang das Wort Data
  • dann die Registernummer
  • zuletzt eine Beschreibung für die Funktion

Transformationen

Bei der bereits erwähnten Transform-Angabe wird ein kleines Javascript benutzt, welches im Verzeichnis /etc/openhab/transform gespeichert werden muss.

// Wrap everything in a function (no global variable pollution)
// variable "input" contains data passed by openHAB
(function(inputData) {
    // on read: the polled number as string
    var DIVIDE_BY = 1000;
    return parseFloat(inputData) / DIVIDE_BY;
})(input)

Hiervon gibt es folgende Varianten:

  • divide1000.js
  • divide100.js
  • divide10.js
  • divide1.js

Die letzte Version wirkt seltsam, macht aber durchaus Sinn, wenn man nur die Umwandlung in Float betrachtet. Für die Nutzung solcher Javascipt-Programme muss das Addon Javascript Scripting aktiv sein.

Nachtrag: Zwei Gründe haben mich bewogen, das oben beschrieben System zu verändern:

  • es gefällt mir nicht, vier Funktionen zu schreiben, die sich nur in einem Parameter unterscheiden
  • gelegentlich liefert der Wechselrichter sehr große oder sehr kleine Werte, die mir die Diagramme versauen. Das Problem tritt z.B. auf, wenn der Speicher leer ist und die Anlage in den Ruhezustand übergeht.
// Binde alles in eine function (globale Variable werden nicht verändert)
// Variable "input" enthält den data string vom binding
// Parameter "by" enthält den Divide-Faktor
// Parameter "von" enthält die untere Grenze
// Parameter "bis" enthält die obere Grenze
// Aufrufbeispiel: JS(divide_by_limit_von_bis.js?by=10&von=0&bis=1000)
// im Beispiel liegt der erlaubte Wertebereich dann zwischen 0 und 100
(function(inputData) {
    if(inputData <= parseFloat(von)) {
      return "UNDEF";
    }
    if(inputData >= parseFloat(bis)) { 
      return "UNDEF";
    }
    return parseFloat(inputData) / by ;
})(input)

Unsinnige Werte werden so nicht übernommen, sondern es bleiben eben Lücken.

Gelegentlich bekommt man aus den Registern Zahlenwerte geliefert, die zu beschreibenden Texten führen. Das ist vor allem bei der ModelID interessant, da die Modellbezeichnung als String nur mühsam auszulesen ist. Für solche Zwecke dienen MAP-Dateien, wie die inverter_modelle.map. Die Datei wird dann in der Read Transform Zeile eingebunden mittels:

MAP(inverter_modelle.map)

Notwendig dafür ist aber auch die Installation des Addons MAP transformation. Beim Erstellen des zugehörigen Items, bei der Einbindung ins Modell, muss dann als Typ auch String gewählt werden.

Für die MAP-Transformationen gab es bei mir immer eine Warnung in der Log-Datei, auch wenn sie funktioniert haben. Ich habe dann die Transformation an dieser Stelle heraus genommen und in den Link-Channel gesetzt. Dort kann man unter Profile den Eintrag MAP anwählen und dann erscheint ein Eingabefeld, in dem man den Dateinamen der Map eintragen kann. Dieser Weg hat ebenfalls funktioniert und es gibt keine zugehörigen Warnungen mehr.

2023-10-05 19.20.31 192.168.1.119 931fb62e5395.png

Einbindung ins Model

Ich habe mir ein Equipment namens Wechselrichter eingerichtet und dann die Funktion Create Points from thing und dann das oben eingerichtete Thing genutzt, um den Wert zu integrieren.

2023-08-31 16.04.10 192.168.1.119 84a6e0eb74ec.png

Im Screenshot sind noch weitere Daten eingebunden, die aus dem gleichen Poll stammen.

Durch die Einbindung entsteht ein Item, das wieder über eigene Eigenschaften verfügt:

2023-08-31 16.11.22 192.168.1.119 85757b46bb19.png

Beim Label bin ich bei meinem Namensprinzip geblieben. Das erleichtert an vielen Stellen die Zuordnung. Erwähnenswert ist noch die Frage, welchen Typ man wählen soll.

2023-08-31 16.11.57 192.168.1.119 26f548fc6406.png

OpenHAB bietet hier eine Reihe von Möglichkeiten an:

Number.ElectricCapacitane:	F
Number.ElectricCharge:		C
Number.ElectricConductane:	S
Number.ElectricCurrent:		A
Number.ElectricInductance:	H
Number.ElectricPotential:	V
Number.ElectricResistance:	Ω
Number.Energy:				kWh
Number.Force:				N
Number.Power:				W
Number.Intensity:			W/qm

Gut passen würde Number.Energy. Das hat aber einen gravierenden Nachteil, durch die Einheit wird das Item quasi zu einem String und muss für Berechnungen konvertiert werden. Ich bleibe also beim einfachen Typ Number und füge die Einheiten über das Meta StateDescription hinzu. Dazu dient die Zeile Pattern mit dem Inhalt

%.3f kW

Darstellung von Werten, für die es eine Beschreibung gibt

In der Regel liefert die Sun2000 Zahlen über die Modbus-Schnittstelle. Für diese Zahlen findet sich dann oft auch ein beschreibender Text. Für die Darstellung des aktuellen Zustandes ist natürlich der beschreibende Text übersichtlicher, für die Diagramme ist Text aber nicht geeignet, hier ist die Zahl und ihr Werteverlauf besser. In diesem Fall erzeugt man einfach zwei Items aus einem Data-Element.

Als Beispiel soll hier das Element Data 32000 Status 1 dienen.

Für das zugehörige Thing habe ich folgende Konfiguration vorgenommen:

2023-12-14 13.28.56 192.168.1.95 e803616eeb03.png

Im Model habe ich dann dieses Thing zweimal über Create Points from Thing in den Bereich Inverter eingebunden.

2023-12-14 13.32.18 192.168.1.95 c17bf2b043dc.png

Die Einbindung erfolgt einmal als Zahl und einmal als Text.

Die Einbindung als Nummer erlaubt Diagramme, die den zeitlichen Verlauf darstellen:

2023-12-14 13.38.10 192.168.1.95 bcc7af5f53f4.png

Die Textversion zeigt die Beschreibung für den aktuellen Zustand:

2023-12-14 13.40.36 192.168.1.95 2778b26cc5d1.png

Hier versteckt sich die spannendste Einstellung aber im Channel Link. Klickt man hier auf den im Screenshot rot markierten Bereich, so öffnet sich die Seite mit den Link-Eigenschaften.

2023-12-14 13.46.08 192.168.1.95 aaa114de9f2c.png

In diesem Fenster kann ich unter Profile auswählen, ob ich die Werte aus dem Thing mit einer MAP oder wie hier mit einem Javascript anpassen möchte. Den Namen der MAP oder des Scriptes gebe ich dann unter Thing To Item Tranformation an, im vorliegenden Fall also status_bit.js

Bei einfachen Wertetabellen bietet sich eine MAP an, hier sind die Zustände aber in einem Bitfeld beschreiben, die Auswertung erfolgt dann über das folgende Javascript:

/etc/openhab/transform/status_bit.js

Identifizierte Register

Eine umfangreiche Liste der Register gibt es von Huawei, die habe ich für diese Seiten aufbereitet und erweitert.

Die Interpretation der Registerinhalte finde ich nicht ganz leicht. Es wird noch eine Weile dauern, bis ich, auch durch Vergleich mit den Angaben aus FusionSolar, alle Beschreibungen richtig interpretiert habe.

Hier eine Liste der Register, bei denen ich mir über die Bedeutung recht sicher bin, die Liste werde ich immer weiter ergänzen.

Text der Überschrift
Register Name Einheit Beschreibung
30070 Model ID - Modell ID
30071 PV Strings - Anzahl der PV Strings
30072 MPP Tracker - Anzahl der Optimierer
32000 Status1 - Zustand des Wechselrichter1
32016 PV1 Voltage V Spannung von String 1
32017 PV1 Current A Stromstärke von String 1
32018 PV2 Voltage V Spannung von String 2
32019 PV2 Current A Stromstärke von String 1
32064 Input power kW Leistung der Module
32078 peak active power today kW höchste heutige Leistung
32080 Active power kW Energieverbrauch im Haus
32087 Internal temperature °C Temperatur im Inverter
37022 battery temperature °C Temperatur der Batterie
37118 Grid frequenzy Hz Netzfrequenz
37758 rated capacity Wh Kapazität der Batterie
37760 SOC % Ladezustand der Batterie
37765 Carge/Discharge Power W Laden/Entladen der Batterie
Beispiel Beispiel Beispiel Beispiel