Neues Modul für Geräte mit Modbus Schnittstelle über RS232 bzw. RS485

Begonnen von StefanStrobel, 12 Juli 2014, 14:50:22

Vorheriges Thema - Nächstes Thema

StefanStrobel

Hallo,

Anbei ein neues Modul für Geräte, die eine serielle Schnittstelle mit Modbus Protokoll haben.
Das ganze besteht aus zwei Teilen: einem Basismodul für die Schnittstelle und Modulen für die daran angeschlssenen Geräte.

Das Basismodul definiert auch Funktionen, die Module für die angeschlossenen Geräte nutzen können. So können Set- und Get-Befehle oder das zyklische Abfragen von Modbus-Registern alles über die Funktionen des Basismoduls gemacht werden. Das Modul für ein Gerät muss dafür nur eine Datenstruktur definieren, in der die Holding-Register des Geräts beschrieben werden.

Beispiel:

my %SET10parseInfo = (
"r256"  =>  { unpack => "n", # 0100 (holding register, hex address 0x0100)
defaultpoll => 1, # request this register in GetUpdate per default
name => "Pb1", # internal name of this register in the hardware doc
showget => 1, # make a get option visible
expr => '$val / 10', # conversion of raw value to visible value
reading => "Temp_Wasser_Ein"}, # name of the reading for this value

definiert ein Holding-Register mit der Adresse 256, in dem die Temperatur des Wassers beim Eintritt in eine Wärmepumpe ausgelesen werden kann. Das Basismodul interpretiert diese Daten und macht daraus ein Reading mit namen Temp_Wasser_ein, eine Get-Option für das Reading, Attribute zum Steuern ob das Register zuklisch abgefragt werden soll etc.


"r770"  =>  { unpack => "n", # 0302
defaultpoll => 1,
name => "ST03",
expr => '$val / 10',
setexpr => '$val * 10', # expression to convert a set value to the internal value
reading => "Temp_Soll",
showget => 1,
min => 5, # input validation for set: min value
max => 32, # input validation for set: max value
set => 1}, # this value can be set


definiert ein Reading mit namen Temp_Soll, das aus dem Holding-Register mit Adresse 770 gelesen werden kann. Das Basis-Modul macht daraus auch eine Set-Option, mit der das Register geschrieben werden kann, eine Eingabeprüfung mit Min- und Max-Wert sowie die dabei nötige Umrechnung.

Weitere Module für Modbus-Geräte sollten so fast ohne nennenswertes Programmieren erstellt werden können.

die Konfiguration am Beispiel der SET Silent 10 sieht dann beispielsweise folgendermaßen aus:


define ModbusRS485 Modbus /dev/ttyUSB1@9600
define PWP ModbusSET 5 60
attr PWP poll-Hysterese 1
attr PWP stateFormat {sprintf("%.1f Grad", ReadingsVal($name,"Temp_Wasser_Ein",0))}


Bisher macht das Basismodul nur Modbus über serielle Leitungen. Modbus-TCP müsste noch ergänzt werden. Das Frame-Format unterscheidet sich dort ein kleines bischen. Ebenso sind bisher nur die wichtigsten Modbus-Function-Codes für Holding-Register implementiert. Für Coils und Inputs müssen sie noch ergänzt werden. Da meine Wärmepumpe alles über Holding-Register abbildet, fehlt mir hier leider das Equipment zum Testen.

Modbus.pm ist das Basismodul
ModbusSET.pm ist ein Modul für die SET Silent 10 Wärmepumpe und ähnliche, die die Steuerung iChill IC121 von Dixell verwenden. Die Pumpe wird auch von Topras unter dem Namen Top10Silent angeboten.

Es würde mich freuen wenn jemand auf dieser Basis weitere Module für Geräte mit Modbus-Schnittstelle bauen kann. ModbusSET.pm sollte gut als Kopiervorlage verwendbar sein. Patches als Vorschläge zur Erweiterung von Modbus.pm für ModbusTCP oder Coils und Inputs werden ebenfalls gerne genommen.

Gruss
   Stefan

Edit 13.2.15: removed attached old versions


Roger

Hallo Stefan,
ich habe einen Stromzähler SDM630M von B+G E-Tech & EASTON erworben. Dieser hat auch eine Modbus Schnittstelle.
Ich habe vor, auf Deinen Vorarbeiten aufsetztend, ein 98_ModbusSDM630M.pm zu schreiben. Aber auch die 98_Modbus.pm muss angepasst werden, da z.B. Modbus function code 4 verwendet wird.
Bist Du hier noch aktiv?

Roger
Zotac, BBB, RPIs mit 10*FHEM
2*HM-LAN, 2*JeeLink, 2*RS485, SignalESP
HomeMatic, PCA301 Komponenten, ModBus: Stromzähler, Fronius WR, Shelly

StefanStrobel

Hallo Roger,

ja, ich bin da noch aktiv und freue mich wenn ich nicht der einzige bin. Ich würde gerne die fehlenden function codes und auch modbus TCP ergänzen. Da ich das selbst aber nicht testen kann, habe ich es erst mal hinten angestellt und gewartet ob es auch jemand brauchen kann.
Möchtest Du Deine Erweiterungen als Diff schicken oder soll ich die Ergänzung machen?

gruss
    Stefan

Roger

Hallo Stefan,
schön zu hören, dass Du hier noch aktiv bist. Ich finde es gut, wenn es ein Basismodul für Modbus gibt. So kann jemand mit mehreren verschiedenen Modbus Geräten alle über einen BUS abfragen/steuern.
Ich schlage folgene Zusammenarbeit vor:
- ich schaue erst mal, dass ich Daten von meinen Stromzähler lesen und interpretieren kann
- wir stimmen neue Anforderungen von "meinem" Gerät gemeinsam ab
- ich erstelle 98_ModbusSDM630M.pm
- Du baust die nötigen Änderungen in 98_Modbus.pm ein
- ich teste mit dann die Funktionalität mit SDM630M


derzeitiger Stand:
- habe in 98_Modbus.pm ModbusSDM630M als Client-Modul aufgenommen
- habe in 98_Modbus.pm Formatierungen zu besseren Verständnis meinerseits vorgenommen
- habe in 98_Modbus.pm etliche print-Befehle eingefügt, damit ich direkt auf der cmd sehe, was passiert
- habe in 98_Modbus.pm object types "r" auf modbus function code "4" umgebogen
- habe in 98_Modbus.pm, sub "Modbus_ParseFrames" die Behandlung von "$fCode==4" eingefügt
- nachdem ich die 120 Ohm Abschlusswiderstände entfernt habe, bekomme ich von SDM630M nun auch Antworten  :)


Nun will ich die Konvertierung der empfangenen Daten (Spannung, Strom) hinbekommen. Die sind nach IEEE754 floating-point numbers, welche als 4 Bytes übertragen werden.


SDM630M unterstützt folgende Modbus-Befehle:
Read Holding Registers     -> function code 3  -> in 98_Modbus.pm parseInfo "r" (Register)
Read Input Registers        -> function code 4  -> in 98_Modbus.pm noch nicht implementiert
Diagnostics                      -> function code 8  -> ich denke Unterstützung benötigen wir nicht
pre-set multiple Registers -> function code 16 -> in 98_Modbus.pm noch nicht implementiert


Frage: Wie soll die Kodierung function code 4 und 16 umgesetzt werden? Derzeit ist folgendes vorgesehen:
my %fCodeMap = (
"read:c" => 1,
"read:i" => 2,
"read:r" => 3,
"write:c" => 5,
"write:r" => 6,
);


Leider ist "i" für input register schon vergeben (oder kannst Du das ändern?).
Dann würde ich gern die Registeradressen in SDM630MparseInfo in HEX eingeben. Wie lässt sich das umsetzten.

So das reicht erst mal. schönes Restwochenende wünscht Roger
Zotac, BBB, RPIs mit 10*FHEM
2*HM-LAN, 2*JeeLink, 2*RS485, SignalESP
HomeMatic, PCA301 Komponenten, ModBus: Stromzähler, Fronius WR, Shelly

ChrisD

Hallo,

Für die Konvertierung der Floats kannst du dich vielleicht bei den Modulen von https://github.com/ChrisD70/FHEM-Modules inspirieren. Diese enthalten Code sowohl für Float-Zahlen im Big-Endian wie auch im Little-Endian Format.

Bei Big-Endian z.B. lässt sich die Zahl mit
$float=unpack "f", pack "L", ($reg0<<16)+$reg1;
umwandeln, wobei $reg0 und $reg1 2 aufeinanderfolgende Register sind.

Grüße,

ChrisD

StefanStrobel

Hallo,

Zitat
Ich schlage folgene Zusammenarbeit vor:
- ich schaue erst mal, dass ich Daten von meinen Stromzähler lesen und interpretieren kann
- wir stimmen neue Anforderungen von "meinem" Gerät gemeinsam ab
- ich erstelle 98_ModbusSDM630M.pm
- Du baust die nötigen Änderungen in 98_Modbus.pm ein
- ich teste mit dann die Funktionalität mit SDM630M
klingt vernünftig.

Zitat
derzeitiger Stand:
- habe in 98_Modbus.pm ModbusSDM630M als Client-Modul aufgenommen
- habe in 98_Modbus.pm Formatierungen zu besseren Verständnis meinerseits vorgenommen
- habe in 98_Modbus.pm etliche print-Befehle eingefügt, damit ich direkt auf der cmd sehe, was passiert
- habe in 98_Modbus.pm object types "r" auf modbus function code "4" umgebogen
- habe in 98_Modbus.pm, sub "Modbus_ParseFrames" die Behandlung von "$fCode==4" eingefügt
Das mit dem $modHash->{Clients} ist in diesem Fall vermutlich sogar überflüssig, da ich nicht das normale 2-stufige Modell verwendet habe. Bei modbus hat das keinen Sinn / Mehrwert gebracht. Man muss ja an der Nachricht nicht erst parsen, für welchen Client die Nachricht ist. Da Fhem der Master ist, ist vom Request her schon vorgegeben, welcher Client gleich drankommt und zudem ist der Client hier fast nur noch ein Pseudo-Modul, das die Datenstruktur zum Parsen füllt. Aber zu Doku-Zwecken hab ich es damals dringelassen :-)

Für das Debugging hab ich mir angewöhnt Log3-Aufrufe mit Level 5 einzubauen und dann in einem zweiten Fenster einen tail -f auf dem Fhem-Logfile offen zu haben. Das hat den Vorteil, dass man nicht alle Print-Aufrufe später wieder entfernen muss und auch später spontan debuggen kann, indem man das verbose-Level je Gerät auf 5 erhöht.

Zu der Map, die vom Lesen/Schreiben und Typ der Daten auf den Function code verweist:

my %fCodeMap = (
"read:c" => 1,
"read:i" => 2,
"read:r" => 3,
"write:c" => 5,
"write:r" => 6,
);


da hatte ich "i" für die discrete inputs zugewiesen, aber da ich die bisher noch gar nie verwendet habe, können wir auch gerne daraus ein "d" machen und dann "i" für die input register verwenden und auf function code 4 verweisen: "read:d" => 2 und "read:i" => 4.

Bei dem 16er code bin ich mir noch nicht ganz sicher wie das am elegantesten zu machen ist. Wenn jedes Gerät den unterstützen würde, könnte man vermutlich generell 16 statt 6 verwenden. Nur das wird nicht immer so sein. Die Idee von der fCodeMap war eigentlich, dass man vom fcode abstrahieren kann und dass das Modul das automatisch richtig macht. Da das aber nicht eindeutig ist, war das so evt. keine gute Idee. Eventuell könnte man auch die fCodeMap abschaffen und statt dessen im Client-Modul ein Flag setzen, welche function codes das jeweilige Gerät unterstützt und dann im Modbus-Modul-Code entscheiden, welcher function code von den unterstützten am elegantesten ist. Bei 4-Byte floats ist 16 vermutlich besser als 6.
Da die function codes 3,4,6,16, 22 und 23 nach meiner Doku die gleichen Registertypen betreffen, wäre das austauschbar ...

Ob man die Adressen in Dezimal oder Hex angibt, ist eigentlich nur eine Geschmacksfrage. Nur müsste man dann entweder nochmal eine weitere Kennzeichnung in den Key des parseInfo hashes einbauen (z.B. rx0a - mit einem extra x) aber das macht die Verarbeitung nachher nicht schneller, oder man ändert die Struktur komplett.
Die idee war hier, dass man beim Parsen der gelesenen Register schnell auf die zuständige Parse-Info zugreifen kann:

my $key = "r$startAdr";
if (defined($parseInfo->{$key})) {
...


Was die float-Typen angeht, so sollten wir erst mal schauen, ob die Formate irgendwie mit f>, f< etc. kompatibel sind. Laut Perldoc kann es da trotz IEEE viele Varianten geben. Im Idealfall funktioniert es direkt wenn in der ParsInfo der richtige unpack-Code eingetragen wird. Kommt aber darauf an, wie Dein Gerät das codiert und sollten wir erst mal prüfen.

Ich werde in den nächsten Tagen leider kaum zum Programmieren kommen, aber sobald ich wieder dazu komme, schau ich mir das im Detail noch genauer an und poste dann eine erweiterte Version des Moduls.

Gruss
   Stefan

Roger

Hi Stefan,
bin am WE weitergekommen. Ich kann jetzt die Input Register mit $fCode==4 auslesen und auch richtig konvertieren.
Ist mir mit:
$val = unpack("f",reverse($rest));
in sub Modbus_ParseRegs gelungen. Es werden 4 Byte übergeben, welche mit dem obigen Befehl dann richtig dekodiert werden. Die Dekodierung habe ich erst mal hart in 98_Modbus.pm eingebaut. Bitte überlege Dir hier eine passende Umsetzung.


Definition %SDM630MparseInfo z.B.

"i000"  =>  {                                 # input register 0x0000, Phase 1: Spannung
unpack => "f", # IEEE 754 floating-point numbers
expr => 'sprintf("%.1f",$val)', # conversion of raw value to visible value
defaultpoll => 1, # request this register in GetUpdate per default
name => "P1_V", # internal name of this register in the hardware doc
showget => 1, # make a get option visible
reading => "P1_V" # name of the reading for this value
},

Den expr mir sprintf habe ich eingefügt, da Fließkommazahlen mit zu vielen Nachkommastellen entstehen. Diese belegen nur Platz, machen es unübersichtlich und bringen keinen genaueren Wert (<Meßfehler). Vielleicht kannst Du in parseInfo etwas einbauen, was dieses kürzer ermöglicht (expr ist ja eigentlich für was anderes gedacht).
Mit der dezimalen Registerangabe bin ich doch hingekommen --> hex ist nice to have  :)

Vielleicht überlegst Du Dir, wie mal in welchem Modul die function codes und die Dekodierung definiert. Vielleicht macht es ja Sinn hier einiges in die Device-Module (z.B. die %fCodeMap) zu verlagern und nur die grundlegende Kommunikation uns Steuerung im Basis-Modul zu machen.
Zitatda hatte ich "i" für die discrete inputs zugewiesen, aber da ich die bisher noch gar nie verwendet habe, können wir auch gerne daraus ein "d" machen und dann "i" für die input register verwenden und auf function code 4 verweisen: "read:d" => 2 und "read:i" => 4.
Heisen die Register bei Deinem Gerät auch Holding und Input register? Dann kann mal vielleicht h und i verwenden.


Als nächstes werde ich mich dem Auslesen der Holding Registern mit $fCode==3 und dem Beschreiben $fCode==15 oder 16 (unterschiedliche Angaben in der Doku) widmen (wohl erst nächstes WE).


Ich berichte, wenn ich weiter bin und stehe dann für gemeinsame Weiterentwicklung und Tests zu Verfügung  :).
Danke für den Tip tail -f (lag schon zu lange zurück  :()
Roger
Zotac, BBB, RPIs mit 10*FHEM
2*HM-LAN, 2*JeeLink, 2*RS485, SignalESP
HomeMatic, PCA301 Komponenten, ModBus: Stromzähler, Fronius WR, Shelly

avg123-de

Hallo zusammen,

ich habe schon seit einiger Zeit vor, einen Stromzähler in FHEM zu integrieren und dachte die ganze Zeit immer wieder an S-Zähler, bis ich auf die Stromzähler mit RS485 gestoßen bin und per Zufall diesen Thread gelesen habe: http://forum.fhem.de/index.php?topic=32354.0

Meine Frage ist, da mein Sicherungskasten und der FHEM-Server ein ganzes Stück auseinander sind und ich in der Hinsicht eigentlich immer relativ flexibel bleiben möchte, was die Positionierung angeht, ob dieses Modul in Zukunft auch die Anbindung über Ethernet unterstützen wird, da dies für mich ausschlaggebend ist.

viele Grüße
Alexander
FHEM auf virtualisiertem Debian in Hyper-V auf Dell Poweredge T110 II mit Windows Server 2012, 1x HM-LAN, verschiedene HomeMatic-Komponenten, Intertechno ITR-1500, Arduino Uno Ethernet mit RF-Modul, DeltaSol BX via VBus, Fritz!Box + Fritz!Fon, SmartVisu via Fronthem, Doorpi

Roger

Hallo Alexander,
also ich werde nichts mit Modbus über TCP/IP machen, da Modbus RS485 mit geschirmter Zweidrahtleitung bis 1200m gehen soll.
Aber Stefan schrieb, dass er sein Modbus-Basismodul 98_Modbus.pm eventuell um IP erweitern will.
ChrisD verweist weiter unten auf https://github.com/ChrisD70/FHEM-Modules, wo ich ein 36_ModbusTCPServer.pm sehe. Vielleicht schaust Du Dich da auch mal um.
Roger
Zotac, BBB, RPIs mit 10*FHEM
2*HM-LAN, 2*JeeLink, 2*RS485, SignalESP
HomeMatic, PCA301 Komponenten, ModBus: Stromzähler, Fronius WR, Shelly

StefanStrobel

Hallo Roger,

Zitat von: Roger am 19 Januar 2015, 19:54:41
Hi Stefan,
bin am WE weitergekommen. Ich kann jetzt die Input Register mit $fCode==4 auslesen und auch richtig konvertieren.
Ist mir mit:
$val = unpack("f",reverse($rest));
in sub Modbus_ParseRegs gelungen. Es werden 4 Byte übergeben, welche mit dem obigen Befehl dann richtig dekodiert werden. Die Dekodierung habe ich erst mal hart in 98_Modbus.pm eingebaut. Bitte überlege Dir hier eine passende Umsetzung.

versuch doch bitte mal im ParseInfo Hash bei unpack "f>" anzugeben. Bei mir (auf einem Raspberry) kommt dann das gleiche heraus wie bei einem unpack("f",reverse($rest)) und es wäre gar keine Code-Änderung nötig.

"i000"  =>  {                                 # input register 0x0000, Phase 1: Spannung
unpack => "f>", # IEEE 754 floating-point numbers - big endian notation
expr => 'sprintf("%.1f",$val)', # conversion of raw value to visible value


im Code bleibt dann das generische:

my $unpack  = $parseInfo->{$key}{unpack};
my $val = unpack ($unpack, $rest);


für die Format-Angabe würde ich vorschlagen, einen weiteren Hash-Key einzuführen (ähnlich habe ich das im FReplacer Modul über Attribute gelöst):

    format => "%.1f",



Zitat
Vielleicht überlegst Du Dir, wie mal in welchem Modul die function codes und die Dekodierung definiert. Vielleicht macht es ja Sinn hier einiges in die Device-Module (z.B. die %fCodeMap) zu verlagern und nur die grundlegende Kommunikation uns Steuerung im Basis-Modul zu machen.

Die CodeMap ins Device-Modul zu verlegen wäre vermutlich die einfachste Lösung um zu definieren, welche function codes eine Modbus-Implementation zum Schreiben von Registern unterstützt. Da der Stromzähler hier den naheliegenden Code 6 nicht implementiert, sondern nur den 16er, müsstest Du dann nur in dem Hash eine Zahl ändern. Gefällt mir fast besser als für jedes Register individuell die zu verwendenden codes anzugeben (das wäre zwar noch flexibler, aber vermutlich unnötig aufwändig).

Zitat
Heisen die Register bei Deinem Gerät auch Holding und Input register? Dann kann mal vielleicht h und i verwenden.



Ich hab gar keine Doku für die SET Wärmepumpe sondern habe mich an den Modbus-Standard Dokus orientiert:
http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf
Wir können aber gerne "h" und "i" nehmen.

In den ParseInfo Hash muss ich auf jeden Fall auch noch einen "Len" Key einbauen. Deine Werte gehen ja über zwei Register. Ich vermute Du hast das erst mal fest als 2 in den Code eingebaut.

Die Dekodierung würde ich im Modbus-Modul lassen. Das sollte alles generisch funktionieren und nicht vom Gerät abhängen.

Ich hoffe ich komme demnächst mal dazu wieder etwas zu programmieren. Diese Woche sieht es schlecht aus.

Gruss
   Stefan

StefanStrobel

#10
Hallo Roger,

anbei mal ein neuer Zwischenstand. Ich habe bei der Überarbeitung auch einige intere Details überarbeitet, Altlasten entfernt (undokumentierte Scan-Funktion) und Übergabeparameter an Funktionen optimiert.
Die Schnittstelle nach Aussen für logische Module hat sich nur so wie bereits diskutiert geändert (r->h, fCodeMap ins logische Modul etc.)
Ich hoffe Du kommst damit klar.

Gruss
   Stefan

Edit 13.2.15: removed attached old versions

StefanStrobel

#11
Hallo,

hier noch mal ein neuerer Stand. Jetzt ist auch "format" als key im parseInfo Hash drin und der function code 16 kann getestet werden.
Zudem habe ich weitere Fehler bei Handling von Datentypen beseitigt und die Funktion zum Parsen von gelesenen Registern optimiert, so dass der "len" key ausgewertet wird. Bei Float-Werten, die über zwei Register gehen, muss len => 2 gesetzt werden und unpack => "f>".
Beispiele / Kommentare zum Aufbau der ParseInfo stehen im ModbusSET Beispiel-Client-Modul

Gruss
   Stefan

Edit 13.2.15: removed attached old versions

Roger

Hi Stefan,
am WE habe ich den Zähler im Zählerkasten eingebaut (vorher war er neben mir nur über einen Stecker testweise an einer Phase angeschlossen). Nun liefert er Werte von allen drei Phasen  :). Mit dem Schreiben zum Zähler habe ich mich noch nicht beschäftig.

Ich versuche gerade Deine neue Version zum fliegen zu bekommen.
Frage: Wie kann ich die Länge beim Lesen definieren (ich muss ja zwei Register hintereinander lesen)? Du hast das was vorgesehen, aber ich blicke es nicht. Habe es erst mal fest in 98_Modbus.pm auf zwei geändert  :(

Ich habe mein Modul in 98_Modbus.pm mit:
$modHash->{Clients} = ":ModbusSET:ModbusSDM630M:"; # Roger
registriert. Ist das notwendig? Müsstes Du es dann für jede Erweiterung tun?

Das entpacken mit unpack    => "f>" funktioniert!  :). Sehr schön, das macht es einfacher.


Also bis auf die Länge geht alles. $fCode=3 und auch $fCode=4. Klasse!   8)

Nun zu den Erweiterungen/Wünschen:
Zitatfür die Format-Angabe würde ich vorschlagen, einen weiteren Hash-Key einzuführen (ähnlich habe ich das im FReplacer Modul über Attribute gelöst):
Code: [Auswählen]

    format => "%.1f",
1. Das mit dem angedachten Format hast Du noch nicht eingebaut?
2. Hast Du Dir schon mal Gedanken zu Einheiten von Werten gemacht? Ich habe hier jede Menge: V, A, W, VA, ...
    Vielleicht kann man die bei den Readings mit angeben. Wenn man ein leerzeichen dazwischen hat, so müssten auch die
    Plots weiter die Wert extraieren, oder? Ev. gibt dann ReadingsVal Probleme, aber es gibt ja das neue ReadingsNum
3. Über defaultpoll=> 1 werden Werte zyklisch ausgelesen - alle mit dem gleichen Zyklus. Einige Werte möchte ich
    gern häufiger lesen, als andere. Hast Du hier Ideen?
4. Wenn das Modul mit einem Intervall gestartet wurde, so gehen manuelle get-Befehle werden timeout häufig nicht
5. Auch ohne Intervall, kann ich nicht nicht mehrere gets absetzten --> z.B. Timeout reading answer for Sum_A

So das reicht erst mal. Vielen Dank für Deine Mühen.
Roger

Zotac, BBB, RPIs mit 10*FHEM
2*HM-LAN, 2*JeeLink, 2*RS485, SignalESP
HomeMatic, PCA301 Komponenten, ModBus: Stromzähler, Fronius WR, Shelly

Roger

Hallo Stefan,
unsere Antworten haben sich überschnitten. Habe die neue Version getestet.


--> Len nun verstanden  ::) und es funktioniert  ;)


$modHash->{Clients} = ":ModbusSET:ModbusSDM630M:"; ist notwendig, sonst funktioniert mein Client Modul nicht. D.h. Du musst jedes neue Client-Modul bei Dir einpflegen.


format klappt auch --> Danke

Fragen 2 - 5 sind noch offen  :D
6. Ich musste bei jedem Register in SDM630MparseInfo die Zeile:
len => 2,# float value, Länge 2 (2 registers / 4 bytes)
einfügen. Kann man das nicht einmal pro Type in %fCodeMap machen?

Roger
Zotac, BBB, RPIs mit 10*FHEM
2*HM-LAN, 2*JeeLink, 2*RS485, SignalESP
HomeMatic, PCA301 Komponenten, ModBus: Stromzähler, Fronius WR, Shelly

StefanStrobel

Hallo Roger,

zu 2) - Einheiten bei Readings. Das Thema wurde schon oft Diskutiert. Siehe http://forum.fhem.de/index.php/topic,18238.msg121212.html#msg121212

zu 3) - unterschiedliche Poll-Zyklen. Was für Zyklen möchtest Du denn verwenden? Ich würda da eher einen sinnvolen Wert für alles suchen und dann gegebenenfalls das Modbus-Modul so optimieren, dass Werte, die man auf einem Schlag lesen kann, auch gemeinsam gelesen werden. Mit function code 3 kann man z.B. bis zu 125 Register lesen, sofern sie nacheinander stehen. Einzelne timer je Reading würden das Konstrukt ziemlich aufblasen.

zu 4 und 5) - timeouts etc. Das kann daran liegen, dass Dein Zähler größere Pausen zwischen zwei Befehlen braucht. Da sollte Dein Modul die Attribute minSendDelay und minCommDelay anbieten. Das Modbus-Modul berücksichtigt die dann bei der Verarbeitung der send-queue. Das kannst Du Dir aus ModbusSET abschauen:

  $modHash->{AttrList}= "do_not_notify:1,0 " .
        "timeout " .
        "minSendDelay " .
        "minCommDelay " .
        $modHash->{pollList} .      # Def der zyklisch abzufragenden Nachrichten
        $readingFnAttributes;


zu 6) - Default-Werte für Keys in der parseInfo, z.B. len. Da überleg ich mir noch eine elegante Variante, wie man Defaults setzen kann. Das könnte auch für format interessant sein, wenn man nur floats hat.

Gruss
   Stefan