Neue Versionen und Support zum Modbus-Modul

Begonnen von StefanStrobel, 20 August 2017, 12:11:08

Vorheriges Thema - Nächstes Thema

Aurel_B

Zitat von: holsteiner-kiel am 14 November 2023, 20:11:51Moin Moin,

Ich hoffe, ich stelle nun keine Frage doppelt, aber dieser thread ist mittlerweile etwas unübersichtlich;)

Ich habe eine tecalor Wärmepumpe und lese per modbusattr erfolgreich Werte aus.

Den Betriebsstatus lese ich per
obj-i02000-reading BETRIEBSSTATUS
aus.

Mit
obj-i02000-unpack B16
bekomme ich als Ergebnis eine bitmaske wie zum Beispiel

0000010000000111

Die letzte 1 steht zum Beispiel für "Schaltprogramm aktiv", die vorletzte für "Verdichter" und so weiter.

Wie kann ich diesen Wert nun in einzelne zerlegen und dann entsprechend zu "Klartext Mappen"?

Die map Funktion kenne und nutze ich. Bin aber unsicher in Bezug auf die "Zerlegung".

Hat jemand eine Idee?

Spontan sehe ich 2 Möglichkeiten: entweder, du interpretierst die Bitmask via ModBusAttr unpack als int etc. Dann bekommst du für jeden möglichen Zustand eine Zahl, die kannst du dann via map auf einen Text mappen. Ist etwas unübersichtlich denke ich da du quasi manuell jeden möglichen Zustand für alle betroffenen Bits durchrechnen müsstest und in map eintragen.
Oder: du machst UserReadings z.B. "Schaltprogramm aktiv" wo du mit Bitwise & alle anderen Bits ausser das letzte ausblendest "$wert & 0000000000000001".

Beides nicht getestet, vielleicht hat jemand noch eine andere Lösung oder eine konkrete Implementation?

holsteiner-kiel

Guter Ansatz!

Vielen Dank dir!

Kleinigkeit fehlt noch zum sauberen Ergebnis:
HEIZEN { ReadingsVal("WP","BETRIEBSSTATUS",0) & 0000000000000100 } ergibt im Reading 64 wenn der Wert für BETRIEBSSTATUS 0000010000000101 ist. Ich denke, er interpretiert das als Zahl und daher kommt das. Evtl. noch eine Idee, wie ich ganz simpel 1 raus bekomme?

Besten Dank!

yoda_gh

Zitat von: holsteiner-kiel am 15 November 2023, 19:35:49Kleinigkeit fehlt noch zum sauberen Ergebnis:
HEIZEN { ReadingsVal("WP","BETRIEBSSTATUS",0) & 0000000000000100 } ergibt im Reading 64 wenn der Wert für BETRIEBSSTATUS 0000010000000101 ist. Ich denke, er interpretiert das als Zahl und daher kommt das. Evtl. noch eine Idee, wie ich ganz simpel 1 raus bekomme?

userReading mit Bitmaske wäre auch mein Ansatz gewesen. :-) Zwei Sachen dazu:

  • Wenn Du 00..00100 schreibst, wird das als Oktalzahl interpretiert (0100 = 64). Wenn Du eine Bitmaske willst, dann musst Du 0b100 schreiben. Meist nimmt man aber Hex, weil kürzer, das wäre dann 0x4. Aber nimm, was Du später besser versteht. :)(
  • Um eine 1 oder 0 zu bekommen, musst Du noch die entsprechende Stellenzahl nach rechts shiften

Also wenn ich Deine Anforderung richtig verstehe, sollte das folgende hoffentlich funktionieren:

{ (ReadingsVal("WP","BETRIEBSSTATUS",0) & 0b100) >> 2 }

holsteiner-kiel

Mega! Das funktioniert! Vielen Dank an euch beiden!

McBasil

#1204
Hallo Stefan,

nach einem fhem-update ist jetz bei mir die Modbus Version vom 7.11. im Einsatz. Jetzt geschehen merkwürdige Dinge:

Du darfst diesen Dateianhang nicht ansehen.

Die meisten Werte sind unsinnig und einfach falsch. Und 40 Sekunden später ist wieder alles ok-Du darfst diesen Dateianhang nicht ansehen.

Ein Blick ins Logfile zeigt auffällig viele Checksum error. Hier ist ein Logfile verbose 5:
Du darfst diesen Dateianhang nicht ansehen.

Sind bei mir jetzt Änderungen erforderlich?

Beste Grüße
Basil



Guzzi-Charlie

Ich versuche gerade einen Modbuszähler vom Typ DS100 (B+G E-Tech) einzubinden. Dazu habe ich (wie schonmal erfolgreich praktiziert) das vorhandene Modul für den SDM630-Zähler verwendet und lediglich die Adressen angepaßt. Leider klappt das diesmal so einfach nicht. Das Modul redet wohl mit dem Zähler, aber die Register passen nicht und die Werte sind ebenfalls unplausibel. Irgendwie muß der "DS100"-Zähler ein anderes Datenhandling haben. Ich habe zwar eine Komplettliste der Registerbelegung, aber zu den Abfragebedingungen habe ich keine weiteren Angaben.

Es gibt ein Windows-Tool mit dem man die Daten problemlos auslesen kann. Da kann man auch die gesendeten Hex-Werte (Senden/Empfangen) sehen, aber mir fehlt leider das Wissen um damit etwas anfangen zu können.

Du darfst diesen Dateianhang nicht ansehen.Du darfst diesen Dateianhang nicht ansehen.Du darfst diesen Dateianhang nicht ansehen.   

Das Tool zeigt hier die original Hex-Werte an die gesendet, bzw. empfangen werden.

01 => Geräte-Adresse
04 => Function-Code (Lesen Input Register)
04 00 => Modbus Register-Adresse
00 02 70 FB => ?
Die Werte für L1 und L2 sind "0" weil ich den Zähler zum Testen nur 1-phasig angeschlossen hatte.

Leider kann ich damit nicht wirklich etwas anfangen. Zumindest scheint die Registerbelegung der Tabelle mit der Realität übereinzustimmen.
- RaspPI 4+: (Cuno V2 -2x KS300, JeeLink -13x EC3000)
- Stromzähler (B+G E-Tech): 6x SDM120M, 9x XTM100A, 38x DRS110M
- LAN: IT LAN-Gateway mit 34x RMF-R1 (Rohrmotor24)
- WLAN: 85x Shelly, 12x Gosund SP111, 16x D1-Mini, 15x Sonoff Basic
- DECT: 6x DECT200, 8x DECT301, - HmIP: 3x FalmotC12, 16x WTH2

appi

#1206
Hallo
ich bräuchte bitte etwas Unterstützung bei der Fertigstellung meines Moduls für die Auswertung per Modbus meiner Heliotherm WP. Es funktioniert eigentlich bereits alles ausser der Umsetzung der Leistungsregister welche 32 Bit lang sind:



Ich bekomme mit der folgenden Definition alle Werte welche vom Format "int16*10" sind perfekt decodiert in die Readings:
'i10' => { reading => 'T_Aussen',
              name => 'Temp. Aussen',
              expr => '$val/10',
              format => '%.1f',
              unpack => 's>',
              poll => 1
},
'i11' => { reading => 'T_Brauchwasser',
              name => 'Temp. Brauchwasser',
              expr => '$val/10',
              format => '%.1f',
              unpack => 's>',
              poll => 1
}, .........etc.

Ergibt die Readings mit den korrekten Werten



Nun zu meinen Problem Registern:

Die Registerdefinition vom Hersteller:
Register  z.B.
68 - 69  0x04     uint32    Stromz_Gesamt
 
Ich bekomme mit der folgenden Definition leider nur die ganzen Zahlen richtig angezeigt aber eben ohne Nachkommastellen:

'i68' => { reading => ' Stromz_Gesamt' ',
              name => ' Stromz_Gesamt' ',
              format => '%.1f',
              len        =>  2,         
              unpack => 'I>',
              poll => 1
},

'i66' => { reading => 'Stromz_Brauchwasser,
              name => 'Stromz_Brauchwasser',
              format => '%.1f',
              len        =>  2,         
              unpack => 'I>',
              poll => 1
},

'i62' => { reading => 'Stromz_Heizung,
              name => 'Stromz_Heizung',
              format => '%.1f',
              len        =>  2,         
              unpack => 'I>',
              poll => 1
}, ..........etc.

Ich glaube alle Varianten getestet zu haben und komm einfach nicht dahinter..... wäre froh um eine Hilfestellung

danke und Gruss
Remo


Aurel_B

Zitat von: Guzzi-Charlie am 29 November 2023, 18:49:55Das Tool zeigt hier die original Hex-Werte an die gesendet, bzw. empfangen werden.

01 => Geräte-Adresse
04 => Function-Code (Lesen Input Register)
04 00 => Modbus Register-Adresse
00 02 70 FB => ?
Die Werte für L1 und L2 sind "0" weil ich den Zähler zum Testen nur 1-phasig angeschlossen hatte.

Leider kann ich damit nicht wirklich etwas anfangen. Zumindest scheint die Registerbelegung der Tabelle mit der Realität übereinzustimmen.

Bei Modbus kommst du um ein wenig rumprobieren kaum herum. Solange du nur lesend auf das Device zugreifst richtest du (soweit ich weiss) auch keinen Schaden an. Schau dir mal meine älteren Posts an, ich würde dir unbedingt QModMaster empfehlen: das ist eine kleine Software, die einen Modbus Server nachstellt. Dort kannst du mit den Registern und den zurückgelieferten Werten spielen. Nach 5-10 Minuten ist die Sache meist selbsterklärend und das übertragen nach FHEM nur noch Fleissarbeit. Beachte, dass bei QModMaster die Registeradressen bei 1 beginnen und bei ModBusAttr bei 0.

Aurel_B

Zitat von: appi am 30 November 2023, 19:16:52Hallo
ich bräuchte bitte etwas Unterstützung bei der Fertigstellung meines Moduls für die Auswertung per Modbus meiner Heliotherm WP. Es funktioniert eigentlich bereits alles ausser der Umsetzung der Leistungsregister welche 32 Bit lang sind:

Nun zu meinen Problem Registern:

Die Registerdefinition vom Hersteller:
Register  z.B.
68 - 69  0x04     uint32    Stromz_Gesamt
 
Ich bekomme mit der folgenden Definition leider nur die ganzen Zahlen richtig angezeigt aber eben ohne Nachkommastellen:

'i68' => { reading => ' Stromz_Gesamt' ',
              name => ' Stromz_Gesamt' ',
              format => '%.1f',
              len        =>  2,         
              unpack => 'I>',
              poll => 1
},



Ähm, das ist ja ein uint32 gemäss Hersteller und damit (positive) Ganzzahl ohne Nachkomma? Damit ist deine format Definition unsinnig. Wenn der Hersteller hier eine Float Zahl mit einer bestimmten Anzahl Nachkommastellen als int liefert, so macht er das meist mit einer Multiplikation vom Originalwert in 10er Potenzen. Sprich: 1 Nachkommastelle == der int Wert ist 10x grösser. Dann müsstest du - so wie du das bei den anderen Registern ja bereits gemacht hast - expr => '$val/10' verwenden um den tatsächlichen Wert mit 1 Nachkommastelle zu erhalten.

appi

Besten Dank

1. Tool QModMaster installiert, wirklich gut, danke.
   - zeigt genau die Werte welche ich im Webinterface der WP sehe, ohne Nachkommastellen.....
   - die Readings welche in FHEM gefüllt werden stimmen
   - die Nachkommastellen kann ich auch mit QModMaster nicht finden

Es gibt eine Implementierung für Home Assistant welche funktioniert und dort habe ich den selben Fehler wie bei mir in den Issues gefunden mit der Lösung:
https://github.com/mbuchber/ha_heliotherm/issues/3#issuecomment-1401513640

[line 378] decoder = BinaryPayloadDecoder.fromRegisters(
[line 379] modbusdata2.registers, byteorder=Endian.Big <----changed wordorder to byteorder
[line 380] )

Daraus die Fregestellung:  Wie kann ich im FHEM Modul  entscheiden ob wordorder oder byteorder benutzt werden soll?
   

Aurel_B

Ich habe die Anleitung rasch überflogen. Ich beziehe mich auch auf deinen Screenshot. Die Registergrösse ist z.B. für die Spannung 2, d.h. du musst 2 ModBus Register auslesen. Als Datentype geben sie INT32(3+3) an, ich glaube damit ist gemeint, dass du im ersten Register die Stellen vor- und im 2 Register die Stellen nach dem Komma hast (je 3). Stell doch mal im QModMaster die Registergrösse auf 2 um und schaue, was passiert. Dann geht es nur noch darum, diese beiden Register in FHEM zusammenzustelllen. Das macht man normalerweise mit "len":

Zitatobj-[cdih][0-9]+-len
defines the length of the data object in registers (16 Bits). It defaults to 1.
Some devices store e.g. 32 bit floating point values in two registers. In this case you should set this attribute to two.
This setting is relevant both in master and in slave mode. The lenght has to match the length implied by the unpack code.
Example: attr MBTest obj-h225-len 2

Falls wirklich die Vor- und Nachkommastellen in 2 aufeinanderfolgenden Register verteilt sind wird das etwas kniffelig, das kenne ich so noch nicht. ABER: ModbusAttr ist super mächtig, irgendwie bekommen wir das hin :-)

StefanStrobel

Hallo Aurel_B und appi,

wenn man Readings aus mehreren Registerwerten zusammenbauen muss, dann ist es wichtig, dass die Register gleichzeitig gelesen werden, sonst bekommt man möglicherweise zwei Werte, die gar nicht zusammen gehören. Über die group-Attribute kann man das steuern.

Gruss
    Stefan

StefanStrobel

Hallo McBasil,

es würde mich wundern, wenn aufgrund eines Fhem-Updates auf einmal Checksum-Fehler kommen. Kannst Du mal auf eine ältere Version zurückgehen um zu verifizieren, ob es wirklich an der Version liegt?
Ist es wirklich das richtige Device und der richtige Adapter, mit denen Du redest?
Wie sieht die Konfiguration aus?

Gruss
   Stefan

Mariomgn

Hallo zusammen,

gibt es die Möglichkeit einzelne Bits in einem Register zu beschreiben/lesen?

z.B.
attr Data4PLC obj-h30[1]-len 2
attr Data4PLC obj-h30[1]-reading Temperatur_Heizung:DS18B20-3_Temperature
attr Data4PLC obj-h30[1]-unpack n
attr Data4PLC obj-h30[3]-len 2
attr Data4PLC obj-h30[3]-reading Temperatur_Heizung:DS18B20-1_Temperature
attr Data4PLC obj-h30[3]-unpack n

ich habe schon verschiedene Schreibweisen ausprobiert, leider ohne erfolg


MfG Mario

McBasil

Hallo Stefan,

sicher hast Du Recht, dass ein Versionswechsel nicht Ursache für die crc-Fehler ist. Es ist wohl mehr so, dass bei mir  normal
verbose auf 1 oder 2 steht und somit diese Fehler nicht protokolliert werden. Und dann fällt mir das natürlich nicht auf. Jetzt war es aber so, dass mit der neuen Version auf einmal jede Menge fehlerhafte Anzeigen erschienen. So wurde mir beispielsweise gleichzeitig angezeigt, dass die Wärmepumpe laufe, aber die Unterwasserpumpe nicht laufe, dass die Warmwassersolltemperatur auf 218 °C eingestellt sei und die Brunneneinlauftemperatur bei 0 °C liege und die Brunnenausgangstemperatur über der Vorlauftemperatur liegt.

Spätestens da setzt man verbose höher und auf einmal werden die Fehler protokolliert und sichtbar.

Jetzt habe ich Ursachenforschung betrieben und die Protokolle ausgewertet. Für mein besseres Verständnis habe ich verschiedene Log-Ausgaben optisch etwas anders aufbereitet. Die Ursache konnte ich ermitteln und beheben. Entscheidend für die Berechnung des CRC-Wertes ist die PDU-Länge. In die Berechnung geht die Anzahl der übermittelten Bytes ein plus 1 für das Längenfeld. In der Funktion   

sub ParseResponse {    wird bei der Berechnung das fcode Byte mitgerechnet und das ist der Auslöser für die fehlerhafte Berechnung.
......
       my ($len, $values) = unpack ('Ca*', $data);
......
       $frame->{PDULEXP}  = $len + 2;                      # 1 Byte fCode + 1 Byte len + len of expected values
muss ersetzt werden durch
       $frame->{PDULEXP}  = $len + 1;                      # 1 Byte len + len of expected values
......
}

Nach dieser Anpassung erfolgt dann die Kontrolle mit der Funktion

sub CheckChecksum {  
....   
    my $data  = $frame->{DATA};
....   
    my $readLen  = length($hash->{READ}{BUFFER});
....   
    if ($proto eq 'RTU') {
        $readLen = length($data);
        my $frLenExp = $frame->{PDULEXP} + $PDUOverhead{$hash->{PROTOCOL}};     # everything including id to crc
        # for RTU Overhead is 3 (id ... 2 Bytes CRC)
        my $crcInputLen = ($readLen < $frLenExp ? $readLen : $frLenExp) + 2;    # PDU plus 2 bytes crc
        my $sent = unpack('v', substr($hash->{READ}{BUFFER}, $crcInputLen, 2));
        my $calc = CRC(substr($hash->{READ}{BUFFER}, 0, $crcInputLen));
        Log3 $name, 4, "$name: CheckChecksum readLen=$readLen, frameLen=$frLenExp (exp $frame->{PDULEXP}, " . 
             "ovr $PDUOverhead{$hash->{PROTOCOL}}), crcdata " . unpack ('H4', pack ('v', $sent)) . " \nBuffer " . ShowBuffer($hash);
....
}      und jetzt werden die CRC fehlerfrei berechnet.

Danach sind die mysteriösen Anzeigen beseitigt, im Protokoll erscheinen keine Fehler mehr und und die Requestquew qlen pendelt sich bei 70 ein.  So ist alles zufriedenstellend.

Beigefügt ist ein Logfile über 6 Minuten und das bei mir aktuell laufende 98_Modbus.pm. 

An dieser Stelle ganz herzlichen Dank für Deine großartige Arbeit.

Beste Grüße
Basil

Du darfst diesen Dateianhang nicht ansehen.
Du darfst diesen Dateianhang nicht ansehen.