« Zurück zu Produkt

Dokumentation

Vorlagen (Dateiformat)

Benötigt: Symcon >= 7.0

Die Instanz "ModBus Gerät" kann ihre komplette Konfiguration als Vorlage exportieren und wieder importieren. Eine Vorlage ist eine JSON-Datei, die alle Adressen, virtuellen Adressen, benötigten Variablenprofile, die Byte-Reihenfolge und die Abfrageeinstellungen enthält. So kann ein einmal eingerichtetes Gerät mit wenigen Klicks auf weiteren Systemen eingerichtet oder mit anderen Nutzern geteilt werden.

Warning

Viele fertige Vorlagen sind in unserer Community zu finden: Vorlagen anzeigen

Auf dieser Seite wird das Dateiformat vollständig beschrieben, damit Vorlagen auch direkt aus dem Datenblatt eines Herstellers erstellt oder per Skript erzeugt werden können.

Import und Export

Aktion Beschreibung
Vorlage exportieren Erzeugt eine JSON-Datei aus der aktuellen Konfiguration. Alle verwendeten Profile, die nicht mit "~" beginnen, werden mit exportiert.
Vorlage importieren Ersetzt Adressen, virtuelle Adressen, Byte-Reihenfolge und Abfrageeinstellungen im Konfigurationsformular. Die Änderungen werden erst mit "Übernehmen" gespeichert. Fehlende Profile werden dabei angelegt, bestehende Profile werden nicht verändert.

Vor dem Import wird die Datei geprüft. Enthält sie nicht die drei Schlüssel "Addresses", "VirtualAddresses" und "Profiles", wird der Import mit der Meldung "This is not a valid ModBus template!" abgebrochen. Existiert ein Profil bereits mit anderen Einstellungen, wird ein Hinweis angezeigt (z.B. "2 profiles do not match!"). Das vorhandene Profil wird in diesem Fall weiterverwendet.

Warning

Beim Import wird die bestehende Konfiguration der Instanz überschrieben. Variablen, deren Ident in der neuen Konfiguration nicht mehr vorkommt, werden beim Übernehmen gelöscht - inklusive ihrer Archivdaten.

Aufbau

Eine Vorlage ist ein JSON-Objekt mit folgenden Schlüsseln:

Schlüssel Typ Pflicht Beschreibung
Addresses Array Ja Liste der Modbus-Adressen, siehe Adressen
VirtualAddresses Array Ja Liste der virtuellen Adressen, siehe Virtuelle Adressen, ggf. leer
Profiles Objekt Ja Variablenprofile, die beim Import angelegt werden, siehe Profile, ggf. leer
ByteOrder Zahl Nein Byte-Reihenfolge der Instanz, siehe Byte-Reihenfolge
Requests Objekt Nein Abfrageeinstellungen, siehe Abfrage

Die Reihenfolge der Schlüssel ist beliebig. Unbekannte Schlüssel werden ignoriert. Eine minimale, gültige Vorlage mit einer einzigen Adresse sieht so aus:

{
    "Addresses": [
        {
            "Active": true,
            "Name": "Battery state of charge",
            "Ident": "battery_soc",
            "Translation": [
                { "Language": "de", "Name": "Batterieladezustand" }
            ],
            "DataType": 2,
            "ReadFunctionCode": 4,
            "ReadAddress": 33139,
            "WriteFunctionCode": 0,
            "WriteAddress": 0,
            "Factor": 0,
            "Length": 0,
            "ByteOrder": -1,
            "Profile": "~Battery.100"
        }
    ],
    "VirtualAddresses": [],
    "Profiles": {},
    "ByteOrder": 0,
    "Requests": {
        "Type": 0,
        "Interval": 5000,
        "DataBlocks": []
    }
}

Adressen

Jeder Eintrag in "Addresses" beschreibt einen Wert des Geräts. Für jeden aktiven Eintrag wird eine Variable unterhalb der Instanz angelegt.

Feld Typ Beschreibung
Active Bool Legt fest, ob die Variable angelegt und der Wert gelesen wird. Inaktive Einträge bleiben in der Vorlage erhalten und können später vom Nutzer aktiviert werden.
Name String Name der Variable. Empfohlen wird ein englischer Name, der über "Translation" übersetzt wird.
Ident String Ident der Variable. Ist das Feld leer, wird der Ident automatisch gebildet, siehe Ident.
Translation Array Übersetzungen des Namens als Liste von Objekten mit "Language" (z.B. "de") und "Name".
DataType Zahl Datentyp des Registers, siehe Datentypen.
ReadFunctionCode Zahl Funktionscode zum Lesen: 0 (nicht lesen), 1, 2, 3 oder 4, siehe Funktionscodes.
ReadAddress Zahl Leseadresse (Startregister bzw. Coil), siehe Adressierung.
WriteFunctionCode Zahl Funktionscode zum Schreiben: 0 (nicht schreiben), 5, 6, 15 oder 16. Ist ein Funktionscode gesetzt, erhält die Variable eine Standardaktion.
WriteAddress Zahl Schreibadresse. Meist identisch mit der Leseadresse.
Factor Zahl Faktor, mit dem der gelesene Wert multipliziert wird. 0 bedeutet "kein Faktor", siehe Faktor.
Length Zahl Nur für Strings: Länge in Byte (2 Byte pro Register). Bei allen anderen Datentypen 0.
ByteOrder Zahl Byte-Reihenfolge dieser Adresse. -1 übernimmt die Einstellung der Instanz, siehe Byte-Reihenfolge.
Profile String Name des Variablenprofils oder leer. Der Typ des Profils muss zum Variablentyp passen, siehe Datentypen.
Warning

Alle Felder sollten immer vollständig und mit dem richtigen JSON-Typ angegeben werden. Zahlen dürfen nicht als String ("3") und nicht als null angegeben werden, sonst schlägt das Übernehmen der Konfiguration fehl. Ausnahme ist "Active": fehlt es, gilt die Adresse als aktiv.

Ältere Exporte enthalten teilweise zusätzliche Felder wie "SwapBytes" oder "CustomFactor". Diese werden ignoriert und können entfallen. Der Wert eines eigenen Faktors steht immer im Feld "Factor".

Datentypen in Vorlagen

In der Vorlage wird der Datentyp als Zahl gespeichert. Die Zahlen sind aus Kompatibilitätsgründen nicht fortlaufend nach Größe sortiert.

DataType Anzeige in der Konsole Register Variablentyp (ohne Faktor)
0 BOOL 1 Bit Boolean
1 UINT8 (MSB) 1 Integer
12 UINT8 (LSB) 1 Integer
2 UINT16 1 Integer
3 UINT32 2 Integer
11 UINT64 4 Float
4 INT8 (MSB) 1 Integer
13 INT8 (LSB) 1 Integer
5 INT16 1 Integer
6 INT32 2 Integer
8 INT64 4 Float
7 FLOAT32 2 Float
9 FLOAT64 4 Float
10 STRING (PLAIN) Length/2 String
14 STRING (HEX) Length/2 String
  • MSB/LSB: UINT8/INT8 lesen ein ganzes Register und verwenden das höherwertige (MSB) bzw. das niederwertige Byte (LSB). So lassen sich zwei 8-Bit-Werte aus einem Register mit zwei Einträgen auf derselben Adresse auslesen.
  • 64 Bit: INT64 und UINT64 werden als Float-Variable abgebildet, da Symcon auch 32-Bit-Systeme unterstützt.
  • STRING (PLAIN): Die Bytes werden als Text interpretiert. Leerzeichen und Null-Bytes am Anfang und Ende werden entfernt.
  • STRING (HEX): Die Bytes werden als Hex-Zeichenkette (Großbuchstaben) dargestellt, z.B. "0A1B". Das ist nützlich für Bitfelder, Versionsnummern oder MAC-Adressen.
  • Faktor: Sobald ein Faktor ungleich 0 gesetzt ist, wird die Variable immer als Float angelegt - auch bei ganzzahligen Datentypen und auch beim Faktor 1.
Warning

Der Typ eines Profils muss zum Variablentyp passen. Ein UINT16-Register ohne Faktor ergibt eine Integer-Variable und kann daher z.B. nicht das Float-Profil "~Watt" bekommen. Soll ein ganzzahliger Wert ein Float-Profil erhalten, kann der Faktor 1 gesetzt werden.

Funktionscodes und Adressen

Funktionscode Richtung Name Erlaubte Datentypen
1 Lesen Read Coils BOOL
2 Lesen Read Discrete Inputs BOOL
3 Lesen Read Holding Registers alle außer BOOL
4 Lesen Read Input Registers alle außer BOOL
5 Schreiben Write Single Coil BOOL
15 Schreiben Write Multiple Coils BOOL
6 Schreiben Write Single Register nur 8/16-Bit-Typen
16 Schreiben Write Multiple Registers alle außer BOOL

Ungültige Kombinationen werden beim Übernehmen mit einer Fehlermeldung abgelehnt, z.B. "Non-Bit values must use function Read Holding Registers/Read Input Registers" oder "Writing in only one register is not possible for multi register values like Int32/UInt32, Int64/UInt64, Float32/Float64, String".

Adressierung: "ReadAddress" und "WriteAddress" sind die Adressen, die tatsächlich im Modbus-Telegramm übertragen werden, beginnend bei 0. Viele Datenblätter verwenden stattdessen die klassische Schreibweise mit Präfix (z.B. 40001 für das erste Holding Register). In diesem Fall muss der Präfix abgezogen werden, siehe Funktionscodes. Andere Hersteller geben die Adressen bereits direkt an (z.B. Solis mit 33000 für ein Input Register). Im Zweifel hilft ein Test mit einem bekannten Wert wie der Seriennummer oder der Netzfrequenz.

Byte-Reihenfolge

Die Byte-Reihenfolge wird für die gesamte Instanz im Schlüssel "ByteOrder" auf oberster Ebene festgelegt. Einzelne Adressen können sie mit ihrem eigenen Feld "ByteOrder" überschreiben. Der Wert -1 übernimmt die Einstellung der Instanz. Die Beispiele zeigen, wie der 32-Bit-Wert 0x11223344 im Gerät übertragen wird:

ByteOrder Bezeichnung Übertragene Bytes Typische Beschreibung im Datenblatt
-1 Von Instanz übernehmen ----------------- nur auf Adressebene
0 Big-Endian (Standard) 11 22 33 44 "High Word first", "ABCD", Modbus-Standard
1 Little-Endian 44 33 22 11 "DCBA"
2 Big-Endian (Byte Swap) 22 11 44 33 "BADC"
3 Little-Endian (Byte Swap) 33 44 11 22 "Low Word first", "Word Swap", "CDAB"

Bei 16-Bit-Werten wirken sich nur 1 und 2 aus (Bytes innerhalb des Registers vertauscht). Für BOOL-Werte ist die Byte-Reihenfolge ohne Bedeutung.

Faktor

Der gelesene Rohwert wird mit "Factor" multipliziert, bevor er in die Variable geschrieben wird. Beim Schreiben wird der Wert vorher durch den Faktor geteilt. Der Faktor ist immer ein Multiplikator: Eine Division durch 10 wird als 0.1 angegeben.

Datenblatt Factor
Einheit 0.1 V 0.1
Einheit 0.01 Hz 0.01
Einheit 10 W 10
Wh, gewünscht in kWh 0.001
kein Faktor 0

Für BOOL- und String-Adressen muss der Faktor 0 sein. Besitzt das Gerät einen eigenen Skalierungsfaktor in einem Register (z.B. SunSpec "Scale Factor"), kann dieser über eine virtuelle Adresse verrechnet werden.

Ident

Der Ident identifiziert die Variable dauerhaft. Ist "Ident" leer, wird er aus Datentyp, Funktionscode und Leseadresse gebildet: A[DataType][ReadFunctionCode]_[ReadAddress], z.B. "A_7_3100". Für virtuelle Adressen wird der Name verwendet, wobei alle Zeichen außer Buchstaben, Ziffern und Unterstrich durch "" ersetzt werden.

Warning

Ohne festen Ident ändert sich der Ident, sobald Datentyp, Funktionscode oder Adresse (bzw. bei virtuellen Adressen der Name) angepasst werden. Die alte Variable wird dann samt Archivdaten gelöscht und eine neue angelegt. Vorlagen sollten daher immer einen festen, sprechenden Ident wie "battery_soc" setzen. Jeder Ident darf nur einmal vorkommen - auch nicht zwischen Adressen und virtuellen Adressen.

Der Ident wird außerdem in den Skripten der virtuellen Adressen verwendet, um auf die Werte zuzugreifen.

Virtuelle Adressen

Virtuelle Adressen berechnen eine Variable per PHP aus den Werten der übrigen Adressen oder verteilen einen geschriebenen Wert auf eine oder mehrere Adressen.

Feld Typ Beschreibung
Active Bool Legt fest, ob die Variable angelegt und die Skripte ausgeführt werden.
Name String Name der Variable
Ident String Ident der Variable. Ist das Feld leer, wird der Ident aus dem Namen gebildet.
Translation Array Übersetzungen des Namens, wie bei den Adressen
VariableType Zahl 0 = Boolean, 1 = Integer, 2 = Float, 3 = String
Profile String Name des Variablenprofils oder leer. Der Profiltyp muss dem VariableType entsprechen.
ReadAction String PHP-Code zum Berechnen des Werts, leer für keine Berechnung
WriteAction String PHP-Code zum Schreiben. Ist er gesetzt, erhält die Variable eine Standardaktion.

Die Skripte enthalten nur den Inhalt einer Funktion, also ohne <?php. Zeilenumbrüche werden im JSON als \n (bzw. \r\n) angegeben.

ReadAction: Wird nach jeder Abfrage ausgeführt. In $VALUES stehen alle Adresswerte als Array mit dem Ident als Schlüssel zur Verfügung. Virtuelle Adressen werden der Reihe nach berechnet und ihr Ergebnis wird ebenfalls in $VALUES aufgenommen - eine virtuelle Adresse kann also auf die Ergebnisse der vorherigen zugreifen. Der Rückgabewert wird in die Variable geschrieben. Wird null zurückgegeben, bleibt die Variable unverändert. Der Rückgabewert muss zum VariableType passen.

return ($VALUES['pv_voltage_1'] ?? 0) * ($VALUES['pv_current_1'] ?? 0);

WriteAction: Wird beim Schalten der Variable ausgeführt. $VALUE enthält den neuen Wert, $VALUES die aktuellen Werte aller lesbaren Adressen. Zurückgegeben wird ein Array mit Ident als Schlüssel und dem zu schreibenden Wert. Für jeden Eintrag wird die Aktion der entsprechenden Adresse ausgeführt, also inklusive Faktor und Datentyp. Wird null zurückgegeben, wird nichts geschrieben.

// Nur die Bits 0-3 eines Bitfelds ändern, alle anderen Bits beibehalten
$current = $VALUES['control_register'] ?? 0;
return ['control_register' => ($current & ~0x0F) | ($VALUE & 0x0F)];
Warning

Der Operator ?? 0 verhindert Fehler, solange eine Adresse noch nicht gelesen wurde oder inaktiv ist. Gibt ein Skript Fehler aus, sind diese im Debug der Instanz unter dem Ident der virtuellen Adresse zu sehen.

Werte werden nur geschrieben, wenn sie sich ändern oder die Variable älter als 60 Sekunden ist. Das gilt sowohl für gelesene Adressen als auch für virtuelle Adressen.

Profile

"Profiles" ist ein Objekt mit dem Profilnamen als Schlüssel. Profile, deren Name mit "~" beginnt, sind Systemprofile. Sie werden nicht exportiert und müssen nicht in der Vorlage enthalten sein. Eigene Profile sollten einen eindeutigen Präfix erhalten (z.B. "Hersteller.Name"), damit sie nicht mit Profilen anderer Vorlagen kollidieren.

Feld Typ Beschreibung
Type Zahl 0 = Boolean, 1 = Integer, 2 = Float, 3 = String
Prefix String Präfix
Suffix String Suffix, inkl. führendem Leerzeichen, z.B. " W"
MinValue Zahl Minimalwert
MaxValue Zahl Maximalwert
StepSize Zahl Schrittweite. Bei schaltbaren Variablen bestimmt sie die Darstellung als Slider.
Digits Zahl Anzahl der Nachkommastellen
Icon String Name des Icons oder leer
Associations Array Assoziationen, jeweils mit "Value", "Name", "Icon" und "Color" (-1 = keine Farbe)

Alle Felder müssen angegeben werden. Der JSON-Typ von "Value" in den Assoziationen sollte zum Profiltyp passen (true/false bei Boolean, ganze Zahl bei Integer).

"Profiles": {
    "Vendor.OperatingMode": {
        "Type": 1,
        "Prefix": "",
        "Suffix": "",
        "MinValue": 0.0,
        "MaxValue": 0.0,
        "StepSize": 0.0,
        "Digits": 0,
        "Icon": "Information",
        "Associations": [
            { "Value": 0, "Name": "Standby", "Icon": "", "Color": -1 },
            { "Value": 1, "Name": "Running", "Icon": "", "Color": 65280 }
        ]
    }
}
Warning

Beim Import werden nur fehlende Profile angelegt. Ein bestehendes Profil mit gleichem Namen wird nicht verändert, auch wenn es abweicht.

Abfrage

Der Schlüssel "Requests" enthält die Abfrageeinstellungen:

Feld Typ Beschreibung
Type Zahl 0 = Einzelne Adressen, 1 = Datenblöcke
Interval Zahl Abfrageintervall in Millisekunden für den Typ "Einzelne Adressen". 0 deaktiviert die Abfrage.
DataBlocks Array Datenblöcke für den Typ "Datenblöcke"

Einzelne Adressen: Im Intervall wird jede aktive Adresse mit gesetztem Lese-Funktionscode einzeln abgefragt. Das ist einfach, erzeugt bei vielen Adressen aber sehr viele Anfragen. Gerade bei Modbus RTU oder langsamen Datenloggern reicht die Zeit dann oft nicht aus.

Datenblöcke: Jeder Datenblock liest einen zusammenhängenden Bereich mit einer einzigen Anfrage und hat ein eigenes Intervall. Anschließend werden alle Adressen aktualisiert, die vollständig im Block liegen und denselben Funktionscode verwenden. So können z.B. Messwerte alle 5 Sekunden und Zählerstände nur jede Minute gelesen werden.

Feld Typ Beschreibung
Function Zahl Funktionscode 1, 2, 3 oder 4
Address Zahl Startadresse
Quantity Zahl Anzahl der Register bzw. Coils (maximal 125 Register)
Poller Zahl Intervall in Millisekunden
"Requests": {
    "Type": 1,
    "Interval": 5000,
    "DataBlocks": [
        { "Function": 4, "Address": 33049, "Quantity": 10, "Poller": 5000 },
        { "Function": 4, "Address": 33161, "Quantity": 20, "Poller": 60000 },
        { "Function": 3, "Address": 43110, "Quantity": 1, "Poller": 10000 }
    ]
}
Warning

Adressen, die in keinem Datenblock liegen, werden beim Typ "Datenblöcke" nicht aktualisiert. Ein Datenblock sollte nur Register umfassen, die das Gerät auch unterstützt - viele Geräte beantworten eine Anfrage mit einer Lücke im Registerbereich mit einem Fehler (ILLEGAL_DATA_ADDRESS) für den gesamten Block.

Checkliste

  • Alle drei Pflichtschlüssel "Addresses", "VirtualAddresses" und "Profiles" sind vorhanden, auch wenn sie leer sind.
  • Jede Adresse enthält alle Felder mit dem korrekten JSON-Typ (keine Strings oder null statt Zahlen).
  • Jede Adresse und virtuelle Adresse hat einen festen, eindeutigen Ident.
  • Namen sind englisch und haben eine deutsche Übersetzung in "Translation".
  • Adressen werden so angegeben, wie sie im Telegramm übertragen werden (ohne 30001/40001-Präfix).
  • Funktionscode und Datentyp passen zusammen (BOOL nur mit 1, 2, 5, 15; Mehr-Register-Werte nicht mit 6).
  • Der Profiltyp passt zum Variablentyp (Faktor ungleich 0 ergibt immer Float).
  • Eigene Profile haben einen eindeutigen Präfix und sind vollständig in "Profiles" enthalten.
  • Selten benötigte Werte sind mit "Active": false enthalten, statt sie wegzulassen.
  • Bei vielen Adressen werden Datenblöcke verwendet und jede aktive Adresse liegt in einem Block.
  • Die Vorlage wurde einmal importiert, übernommen und wieder exportiert. Der Export muss dieselben Adressen enthalten.
Haben Sie noch Fragen?