Loxone Config – Modbus synchron lesen

Über Modbus-TCP Register blockweise lesen

Dieser Artikel behandelt das synchrone/blockweise Lesen von Registern über Modbus-TCP in der Loxone Config. Es können beliebig viele Register mit unterschiedlichsten Datentypen gleichzeitig gelesen und angezeigt werden. Dieser Artikel führt zum einen die Informationen der mehrteiligen Reihe zusammen, zum anderen enthält er Verbesserungen, Beispiele und bietet die Sourcen (v26) zum Download an.

Teil 1 dieser Reihe hatte sich noch damit beschäftigt Register mit bis zu 64 Bit zusammenhängend/gleichzeitig zu Lesen, mittels Loxone-Bordmitteln zu verarbeiten und daraus entweder 2 oder 4 Werte herauszurechnen und anzuzeigen. Ab Teil 2 war der Ansatz dann vollständig picoC basiert und ging weit über 64 Bit hinaus: Auslesen, Auswerten, Anzeigen.

Die Kurzfassung der vorliegenden Lösung lautet: Mit dem Einsatz dieser Implementierung kann man größere Mengen aufeinanderfolgender Register synchron/blockweise lesen und selektiv beliebige Werte daraus anzeigen, unabhängig von deren Datentypen. Die aktuellsten Sourcen hierzu finden sich am Ende dieses Artikels. Und wer frühere Versionen kennt: Es gibt keine Instabilitäten mehr bei Speicherungen.

Nun zur Langfassung… 🙂

Wozu das Ganze, was sind die Anwendungsmöglichkeiten?

  1. Am offensichtlichsten und meistdiskutiertesten ist mit Sicherheit das Thema mit den Skalierungsfaktoren. Werden Werte asynchron zu deren Skalierungsfaktoren gelesen, kann es zu temporären Ausreißern führen. Datenerfassung, Zählerbausteine, Grafiken, Statistiken – allesamt betroffen.
  2. Auch manche fachliche Werte müssen zeitgleich gelesen werden, um vernünftige Berechnungen oder Auswertungen machen zu können. Sie ergeben nur mit den korrekten Pendants Sinn. Ich gehe jetzt nicht darauf ein, aber einige Begriffe hierzu wären: Verlustleistungen, Wirkungsgrade, Phasenleistungen, Volt/Amp/Watt, Umwandlungswerte AC/DC etc..
  3. Viele Einzelabfragen belasten das Device zudem mehr als einige wenige Abfragen, im Idealfall vielleicht sogar nur eine einzige.

Und was kann die Lösung nun?

Ausgehend von einer Startadresse wird eine Menge an definierten Bytes gelesen. Genauso wie bei diversen Modbus-TCP Tools aus dem Internet. Im Unterschied zu diesen können Werte jedoch auch selektiv ausgeblendet und damit nur die relevanten dargestellt werden. Unterstützt werden die Modbus Funktionen

  1. Read Holding Registers (03)
  2. Read Coils (01)

Sofern reservierte Bereiche im gelesenen Block liegen, muss man gerätespezifisch handeln. Manche Geräte lassen ein Lesen ohne Fehler zu, andere nicht. Also einfach einmal testen oder die Doku lesen.

Mit Blick auf das nachstehende Bild mit einer beispielhaften Darstellung für das Lesen und Anzeigen von Registern und Coils zunächst eine allgemeine Erklärung. Details finden sich dann in den Beispielen weiter unten. (Mit einem Klick auf das Bild wird es lesbar. 🙂 )

Von links nach rechts:

  • Zunächst sieht man oben links im Bild einenTextgenerator-Baustein, welche die Konfiguration zum Lesen von Registern enthält. Darauf wird gleich eingegangen.
  • Die Konfiguration wird an den ersten Programm-Baustein an 5 Eingangskanäle (T1-T3,I1 und I2) angeschlossen. Dieser liest dann über Modbus-TCP Daten aus dem Device und zeigt diese an den Ausgabekanälen O1-O13 an. Reichen diese nicht aus, so werden die Daten an den nächsten Baustein weitergereicht und dort angezeigt. Einfach einen weiteren Programm-Baustein samt picoC Code einfügen, Aus-/Eingang verbinden, durchstarten, fertig. Aktuell stehen maximal 65 Anzeigekanäle oder 260 Byte zur Verfügung. Neben dem Hauptbaustein können also noch 4 weitere Bausteine zur Anzeige angeschlossen werden.
  • Ein ähnliches Vorgehen findet sich im unteren Teil des Bildes. Dort werden Coils synchron gelesen und angezeigt. Details hierzu in Beispiel 3.

Noch ein paar Worte zum Textgenerator-Baustein(Tr-Eingang aktivieren! 🙂 ):

  1. IP, Port und Modbus Id
    • Wird nach dem Port nichts mehr angegeben, so wird DeviceId 1 angenommen. Eine andere ModbusId kann kommasepariert angegeben werden. Mit einer Id von 3 also z.B. 192.168.1.10:502,3
  2. Startadresse: Die Angabe der Adresse wird zunächst als vierstelliger Hex-Wert interpretiert. Einfach eine „8000“ zu schreiben wäre also eine dezimale 32768. Um das klarer anzugeben ohne einen Rechner bemühen zu müssen, kann man sowohl in dezimal(„d:“) als auch in hex(„h:“) arbeiten. Beispiele hierfür: 9CFE, h:9CFE, d:40190
    • Nachstehend unterschiedlich dargestellt mit demselben Ergebnis:
  3. Datentyp-Angaben(darauf wird in den Beispielen eingegangen)
    • Per Default wartet das Programm 1000ms auf die Antwort des Devices, bevor die Verarbeitung der Antwort beginnt. Kann das eigene Gerät schneller oder eben langsamer antworten, so kann man den Datentypangaben noch in ms die Wartezeit auf eine Antwort voranstellen. Bei zum Beispiel 500ms könnte die Datentypangabe dann so aussehen: 500:5x2,4x9,5x2,2x9,15x2
  4. Datenformat der Antwort: Angabe, in welchem Format das Device antwortet: Big-Endian(=1) oder Little-Endian(=0)
  5. Wartezeit zwischen zwei Anfragen in ms. Wird nichts angegeben, so liegt der Default bei 10 Sekunden, also 10000ms.

Darstellung von Werten

Die Anzeige der Registerwerte muss nicht zwangsweise dem komplett gelesenen Registerblock entsprechen. Man kann z.B. 40 Werte als Block synchron lesen und nur den ersten und den letzten Wert ausgeben. Wie das?

Die Daten müssen zwar zusammenhängend aus dem Gerät ausgelesen werden, aber in der Anzeige kann man selektiv sein. Dafür gibt es die eingeführten Pseudodatentypen IGNORE16, IGNORE32 und IGNORE64. Man kann also z.B. einen Bereich mit 40 Werten auslesen, dann aber gezielt Werte ausblenden bzw. anzeigen. Damit kann man dann auf unwichtige Werte verzichten. Weitere Infos gleich in Beispiel 1.

Unterstützte Datentypen

Generell werden drei verschiedene Arten von Datentypen unterstützt: Numerische Datentypen(1-11), Strings(12,13) und Coils (also Bit-Register, 14). Zu jede dieser Arten findet sich dann gleich ein Beispiel. Die unterstützten Datentypen sind im Detail:

1 = UINT16
2 = INT16
3 = UINT32
4 = INT32
5 = UINT64
6 = INT64
7 = FLOAT16
8 = FLOAT32
9 = IGNORE16
10 = IGNORE32
11 = IGNORE64
12 = STRING16
13 = STRING32
14 = COIL

Die nun folgenden ersten beiden Beispiele sind mit einem SolarEdge Wechelrichter umgesetzt, das letzte Coil-Beispiel mit einer Wärmepumpe. Für den SolarEdge Wechselrichter gibt es einschlägige Registerdokumentation, in der die dargestellten Adressen/Werte/Einheiten entsprechend dokumentiert sind.

Beispiel 1 – 48 numerische Werte synchron auslesen und 39 anzeigen

Auf die allgemeine Konfiguration im Textgenerator-Baustein wurde bereits eingegangen. Deshalb die Konzentration auf die Datentyp-Konfiguration. Diese Variante hier ist anwendbar für die Datentypen 1 bis 11 aus der Liste:


Der Konfiguration sagt dem Programm nun:

Startend bei der Dezimal-Adresse 40190 werden in Summe 48 Registerwerte ausgelesen, aber nur 39 angezeigt. Das passt hier im Beispiel genau auf die 3×13 Ausgabekanäle. Muss aber natürlich nicht passgenau sein. Auf das Ergebnis wird 800ms gewartet. Die Erläuterung der Werte im Detail.

  • 5 Werte vom Datentyp „2“(INT16)
  • 9 Werte mit Pseudodatentyp „9“(IGNORE16)
  • 22 Werte vom Datentyp „2“(INT16)
  • 8 Werte vom Datentyp „3“(UINT32)
  • 1 Wert vom Datentyp „2“(INT16)
  • 3 Werte vom Datentyp „3“(UINT32)

Die numerischen Datentypen 1 bis 11 aus der Liste können beliebig vermischt werden. Man kann also FLOAT, INT mit 16, 32 oder 64 Bit in beliebiger Reihenfolge gleichzeitig abgreifen, sofern diese in einem zusammenhängenden Adressblock auf dem Device verfügbar sind.

IGNORE16 sorgt dafür, dass zwar 2 Byte gelesen, aber nicht angezeigt werden. Würde man also z.B. einen FLOAT32 Wert „überspringen“ wollen, so würde man 2×9 oder auch 1×10 angeben. Entsprechend beim Ignorieren von z.B. zwei FLOAT32 und einem UINT16 Wert dann 5×9 oder 2×10,1×9.

Das Sizing ist derzeit so, dass max. 65 32-Bit Werte angezeigt werden können(gelesen werden können mehr). Gemischt mit 64-Bit Werten dann eben entsprechend ein bisschen weniger. Wer mehr Ausgabekanäle benötigt sollte mich kontaktieren bzw. ernsthaft überlegen, ob der Anwendungsfall für Loxone geeignet ist… 🙂

Sinnvollerweise hat man natürlich eine passende Dokumentation der Register neben sich. Hier noch ein Beispiel für ein weiteres Mapping der Batterie-Register.

Wird das Ganze dann auf den Miniserver übertragen und das Programm beginnt zu laufen, werden je nach Stand folgende Informationen im linken Hauptbaustein angezeigt.


1) Lesen der Bytes über Modbus-TCP

Aktives schicken der Anfrage und Lesen der Ergebnisbytes. Frühere Versionen hatten in dieser Phase Instabilitäten, sofern man gleichzeitig neue Konfigurationen einspielen wollte. Das ist jedoch behoben.


2) Wartezustand und Statusinformationen

Nach der Verarbeitung wird „Reading ok“ ausgegeben und die Werte werden auf den Ausgabekanälen angezeigt, samt deren passenden Registeradressen wie im Bild dargestellt. Gerade beim Überspringen von Adressen zur Kontrolle hilfreich. Hat man die Adresse in Hex-Format angegeben, so erfolgt die Ausgabe ebenfalls in Hex-Format, ansonsten dezimal.

Zur besseren Übersicht wird zudem die Anzahl an auszugebenden Werten(nicht Bytes) angegeben.

Beispiel 2 – Auslesen und Anzeigen von 4 Werten vom Datentyp String

Liest man String-Datentypen aus, so werden diese am Ausgang „Txt2“ des ersten Programm-Bausteins gesammelt ausgegeben. Sie dienen ohnehin nur zur Info und so viele Textausgänge gäbe es auch gar nicht.

Hierfür wird ein Textgenerator-Baustein mit einer Startadresse(hier d:40123) erstellt und angeschlossen. Im Beispiel ist es eine Mischung aus STRING16 und STRING32 Datentypen. Und ein UINT16 wird ebenfalls noch angezeigt.

Beispiel 3 – 13 Coils synchron auslesen und anzeigen

Coils sind Bit-Register und von daher anders zu behandeln. Die Anzeige sollte deshalb nicht mit „normalen“ Registern vermischt werden. Wenn z.B. 9 Coils gelesen werden, dann sind hierfür 2 Byte an Daten notwendig, wobei vom zweiten Byte dann nur das erste Bit relevant ist.

Mit diesem Wissen nun zum Beispiel mit 13 Coils. Die Ausgabe an den Kanälen erfolgt so, dass jeweils ein Byte an einen Ausgang gelegt und ein Loxone Binärdekoder angeschlossen wird. Sieht im Ergebnis dann folgendermaßen aus:

Ich lese hier startend bei der dezimalen Registeradresse 80 also 13 Coils(Datentypwert 14) synchron aus und lasse diese anzeigen. Alternativ kann man als Adresse natürlich auch in Hex „h:0050“ angeben. Die Ergebnisse rechts sind im Screenshot von oben nach unten zu lesen. Das erste Bit entspricht also dem Wert von Register 80, das nächste 81 usw..

Wer mag – die Sourcen

Für den linken Programm-Baustein mit der Modbus-Connection nachstehend der picoC-Code. Wer eine Version bis einschließlich v25 einsetzt, muss bei einer neueren Version seine Datentyp-Konfiguration überprüfen. Es gab hier nicht rückwärtskompatible Änderungen.

Für die weiteren Programm-Bausteine wird ein Decodier- und Anzeigecode benötigt. Nachstehend zum Download.



Für Deepdiver: Wer sehen möchte, welche Modbus Bytesequenzen gesendet/empfangen werden, der kann im „reading“-Code den Debugmode aktivieren. Es werden dann in der Loxone Config-Oberfläche entsprechende Ausgaben gemacht.

Feedback ist natürlich jederzeit willkommen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert