Neue Versionen und Support zum Modbus-Modul

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

Vorheriges Thema - Nächstes Thema

StefanStrobel

Hallo Ralf,

ich denke ich habe das Problem verstanden.
Folgendes erkenne ich im Log:
Zitat
2021.07.08 11:16:51 4: DUPATTR: ProcessRequestQueue (V4.4.02 - 31.3.2021) qlen 1, sending 050206300001b8c9 via /dev/serial/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.4:1.0-port0@57600,8,N,1, read buffer empty,
request: id 5, read fc 2 d1584, len 1, master device DUPATTR, reading Schreibtischlampeneu (getUpdate for Schreibtischlampeneu len 1), queued 0.00 secs ago
2021.07.08 11:16:51 5: DUPATTR: Send called from ProcessRequestQueue
2021.07.08 11:16:51 5: SW: 050206300001b8c9
Das Modul schickt einen korrekten Request für einen einzelnen Digital Input mit Adresse 1584.

Zitat
2021.07.08 11:17:06 5: DUPATTR: readFn buffer: 050202000189b8
Es kommt eine gültige Antwort vom Device mit zwei Bytes als Daten: 00 01
Das ist schonmal seltsam, denn es war ja nur 1 Input angefragt und der passt in ein einzelnes Byte ...

Zitat
2021.07.08 11:17:06 5: DUPATTR: SplitDataString called from ParseDataString with data hex 0001, type d, adr 1584, valuesLen 1, op read
2021.07.08 11:17:06 5: DUPATTR: SplitDataString shortened coil / input bit string to 0, start adr 1584, valuesLen 1
2021.07.08 11:17:06 5: DUPATTR: CreateDataObjects called from ParseDataString with objList d1584
2021.07.08 11:17:06 5: DUPATTR: CreateDataObjects sortedList d1584
2021.07.08 11:17:06 5: DUPATTR: CreateDataObjects unpacked 30 with a to 0
2021.07.08 11:17:06 4: DUPATTR: CreateDataObjects assigns value 0 to Schreibtischlampeneu

Das Modul geht wie im Modbus-Standard beschrieben davon aus, dass im ersten Byte der angefragte Input steht und kürzt das folgende vermeintlich überflüssige Byte weg.

siehe: MODBUS Application Protocol Specification V1.1b3 Modbus / http://www.modbus.org
Zitat
6.2 02 (0x02) Read Discrete Inputs
This function code is used to read from 1 to 2000 contiguous status of discrete inputs in a
remote device. The Request PDU specifies the starting address, i.e. the address of the first
input specified, and the number of inputs. In the PDU Discrete Inputs are addressed starting
at zero. Therefore Discrete inputs numbered 1-16 are addressed as 0-15.

The discrete inputs in the response message are packed as one input per bit of the data field.
Status is indicated as 1= ON; 0= OFF. The LSB of the first data byte contains the input
addressed in the query. The other inputs follow toward the high order end of this byte, and
from low order to high order in subsequent bytes.

If the returned input quantity is not a multiple of eight, the remaining bits in the final d ata byte
will be padded with zeros (toward the high order end of the byte). The Byte Count field
specifies the quantity of complete bytes of data.

Im Standard ist sogar noch ein Beispiel abgebildet um das zu verdeutlichen.
Zudem habe ich das ganze kurz mit einer anderen Modbus-Implementation verglichen und da kommt auch ein einzelnes Byte als Antwort.

Ich interpretiere das so, dass Doepke hier eine Abweichung vom Modbus-Standard implementiert hat.
In deren Doku auf Seite 13 steht es auch so (mit einem vorangestellten "dummy-Byte") drin, daher ist das nicht einfach ein Bug, sondern eine eigene Protokoll-Variante.
Es würde mich interessieren, wie andere Modbus-Master damit umgehen.

Ich habe schon mehrere Fälle von Standard-Abweichungen im Fhem-Modbus-Modul eingebaut.
Für diesen Fall kann ich das auch als Attribut machen, z.B. "attr DUPATTR broken-fc2 doepke"
und dann wird das erste Byte verworfen oder die Reihenfolge der Bytes vertauscht (da wäre es schön zu wissen, wie das Device antwortet, wenn 10 Eingänge gleichzeitig abgefragt werden...

Gruss
   Stefan


RaKoHe

Moin Stefan,

das hört sich super an.
Ich habe den ganzen Tag probiert, ohne ein Ergebnis :'(

Ich probiere es gerne aus:-)

Mit sonnigen Grüßen

Ralf

StefanStrobel

Hallo Ralf,

hier ist eine neue Version zum Testen, die ein zusätzliches Attribut für diesen Zweck versteht:

attr DUPATTR dev-d-brokenFC2 doepke


probier das doch mal aus und poste das Log. Ich hab ja kein Doepke-Gerät zum Testen.

Gruss
   Stefan



RaKoHe

Hallo Stefan,

funktioniert auf Anhieb.
Teste jetzt mehrere Register, Rückmeldung vermutlich erst morgen ;D

Vielen Dank für den super Service!

Ralf

claudio

This is a personnal message for @StefanStrobel

I post it there at your demand. I hope to be in the right thread.

This post is concerning the abnormaly high cpu usage while polling one modbus device every 1 sec.  Right now, I read 20 registers but the setup is not completed yet. I stopped when I discovered the cpu usage increase. I've tried to read the same registers on the same machine (a raspberry pi 2) not with fhem but with a test program in java (using de.re.easymodbus.modbusclient library and jssc serial library), and a faster poll of 500ms, the cpu usage is way lower, in the range 0.5-1.5% CPU for the process.

Problem is I need to deal with the data in fhem and the I would need to find a way to pass data from this app to fhem... seems pretty ugly but could work. The best would be to have everything in fhem.

Joined are the files you asked,

Thanks you in advance

StefanStrobel

Hello Claudio,

thanks for posting the files.
The Modbus module has beed designed to be very flexible and allows a lot of generic options which make it cpu intensive.
In addition the Fhem framework and every event in the framework adds to that.
But I will have a close look your scenario and check if there is a way to reduce the cpu load.

regards,
   Stefan

StefanStrobel

Hello Claudio,

I noticed that you didn't define a polldelay for your objects.
Currently this defaults to 0.5 seconds which probably is a problem in your use case.
Please define something like 0.1 as polldelay for all your objects.
I will make a dev-defPolldelay attribute available in the next release to make this easier.
Until then this would need to be defined individually.
Also to make understanding your problem easier, it would help a lot if you can specify

attr global mseclog 1

and the post another log. Otherwise I can't really see where most of the time is lost in your case.
I've bee trying to simulate it but since I don't have your device, I can only guess some things.

It would also help if you can disable events temporarly to see if the problem really lies in the modbus device or if the frequent events just slow down the fhem platform. Just replace your event-on-change-reading with event-min-interval 600 to see how that changes the load and processing time.

regards,
   Stefan

claudio

Zitat von: StefanStrobel am 11 Juli 2021, 13:58:20
Hello Claudio,

I noticed that you didn't define a polldelay for your objects.
Currently this defaults to 0.5 seconds which probably is a problem in your use case.
Please define something like 0.1 as polldelay for all your objects.
I will make a dev-defPolldelay attribute available in the next release to make this easier.
Until then this would need to be defined individually.
Also to make understanding your problem easier, it would help a lot if you can specify

attr global mseclog 1

and the post another log. Otherwise I can't really see where most of the time is lost in your case.
I've bee trying to simulate it but since I don't have your device, I can only guess some things.

It would also help if you can disable events temporarly to see if the problem really lies in the modbus device or if the frequent events just slow down the fhem platform. Just replace your event-on-change-reading with event-min-interval 600 to see how that changes the load and processing time.

regards,
   Stefan

thanks Stefan

I tried what you suggested, setting polldelay on all objects : it doesn't make things better, quiet the opposite, I see between 1-3% CPU increase
attr Satel_ACU220 obj-h0-polldelay 0.1
attr Satel_ACU220 obj-h1-polldelay 0.1
etc...

My observations:
- if I remove event-on-change-reading and set event-min-interval for all ModbusAttr objects: (.*:600) I dont see any gain in cpu %, the cpu usage remain the same

- the suppression of associated notify has no effect on cpu usage

- if I use a modbus proxy like https://github.com/3cky/mbusd which convert modbus serial to tcp and setup fhem to use an ip to connect to modbus, DEF : 5 1 127.0.0.1:502 TCP I observe no improvement in cpu usage.

- I Transfered the modbus slave near my main FHEM (running on a raspi 4, instead of raspi2 for tests), with the exact same fhem config, the cpu is still high but lower (near 10%, instead of 23% on raspi2)

- with a virtual machine (x86 vmware) running ubuntu 18.04 LTS, a test fhem instance without much device, just the modbus in tcp mode I see just 0.3 - 0.7 % cpu usage for fhem but the processor is way more powerful

- disabling the modbus master ModbusAttr, fhem goes back between 0.3 and 1.7 % cpu usage on raspi4 and raspi2

files joined:
about 1 minute of log each. I generated an event on log1 with a remote control received on the slave device ACU-220

claudio

#803
@StefanStrobel
One little question about RS-485 serial interface:

I found this : https://home.hottis.de/gitlab/wolutator/modbusmaster

the pcb use a RS485 chip LTC485 which I have personnally in my parts but not actually used. This chip use a GPIO on master device (arduino, pi whatever) connected to it's RE (Receiver Output Enable) and DE (Driver Output Enable) pins. According to this site,quote: "TX is at GPIO14, RX is at GPIO15 and RTS (control line for transmitter enable) is at GPIO17."

the rs485 device I currently use doesn't have any rts or cts pin on serial interface, only RX,TX,VCC,GND but it appear to work

Did fhem modbus make use of RTS and how to configure it ? I don't seen options in module to set it up. Can't you light me up ?

StefanStrobel

Hello Claude,

I'm trying out a few optimisations / caching of structures in the module to speed things up, up it is probably not going to be a massive improvement. I'll post an update when I'm through with it.
Regarding the rs485 interface, I have used probably 5 to 10 different cheap usb tp rs485 adapters from ebay / aliexpress in the past and most worked. The module doesn't care about setting individual hardware flow control but relies on the underlying fhem / os routines to do that.
In most cases it's an ftdi chip that drives usb to serial which also controls RE / OE on the RS485 driver chip (e.g. a max485)

I hope this helps.

regards,
    Stefan

StefanStrobel

Hello Claude,

can you please test the attached new base module and set the attributes

attr Satel_ACU220 cacheUpdateHash 1
attr Satel_ACU220 cacheParseInfo 1


cacheUpdateHash will cache all info needed when preparing a new request round. PollDelay will not be available if this is used, but it should speed up the request creation when it is done the second time and later.

cacheParseInfo will save a little time when the same object is retrieved the second time and later.

It is not going to decrease cpu load a lot. On my system it is hardy measurable but maybe on an old Pi 2 it can make a difference.
In any case I would recommend to use a decent cpu ;-)

regards,
   Stefan



claudio

#806
Zitat von: StefanStrobel am 13 Juli 2021, 20:29:09
Hello Claude,

can you please test the attached new base module and set the attributes

attr Satel_ACU220 cacheUpdateHash 1
attr Satel_ACU220 cacheParseInfo 1


cacheUpdateHash will cache all info needed when preparing a new request round. PollDelay will not be available if this is used, but it should speed up the request creation when it is done the second time and later.

cacheParseInfo will save a little time when the same object is retrieved the second time and later.

It is not going to decrease cpu load a lot. On my system it is hardy measurable but maybe on an old Pi 2 it can make a difference.
In any case I would recommend to use a decent cpu ;-)

regards,
   Stefan

Thanks Stefan.

I've tried your test version of the module with associated attributes but unfortunately, I didn't see any improvement in cpu usage. I now test exclusively on a raspi 4.

2 things I may mention : First, about 1 week ago, I tested a configuration that appeared to have nearly no impact on cpu, even on a raspi2. It may give you a clue of what's going on. I've programmed an Arduino uno atmega328p to poll the slave with the same registers setup in fhem. The arduino job was only to poll the slave, it wasn't doing anything with the data. Then in fhem, I've setup modbusattr as a passive listener. The registers where updated continously with nearly no impact on cpu.
I've reverted to master mode on fhem because I needed to send data to the slave at times and this is not possible in passive mode.

EDIT: redone the tests, it has the same performance impact when fhem is in passive listener mode.  I was mislead by the fact I did not have the same amount of readings to process

Second, I've tried to setup fhem in slave mode and put the arduino in master mode. The arduino was still polling the satel slave but in the same time, if a register had changed since the last iteration poll, the arduino would then send the data to the fhem slave. this worked, albeit, I needed to insert delay in the code between reading a device and sending to another. But the most intriguing fact is that fhem showed also a significant raise in cpu usage, I don't recall the exact values, but it was in the same league. this is strange since the cpu was high even when no new data was incoming.
Could this be related to the way that fhem deal with serial ports ??

StefanStrobel

Hello Claude,

why don't you set fhem globally to verbose 5 and then watch the log.
If fhem does nothing else as slave, there should be no activity in the log while no data is received.
This should explain what's happening ...

regards,
   Stefan

laserrichi

Sprung in eine sub routine mit Wertübergabe klappt nicht so richtig.

Ich möchte in einer subroutine springen und den aktuellen wert übergeben, dazu habe ich folgendes probiert:
          "i12801" =>  {       'reading' => 'SolarladerStatus',
       'unpack' => 'B16',  # zerlegen in 16 bits
               'expr' => '$val=(ModbusEPEVER_laderstatus($val))' #übergabe an die sub


in der sub nehme ich den Wert entgegen:
sub ModbusEPEVER_laderstatus($)
{
my ($inputa) = $_;


jedoch ist der inhalt $inputa  ein komplett anderer, und zwar irgendwelche http aufrufe.
wie bekomme ich die gefüllte variable in die sub?
RaspberryPi 4 Bullseye,Homematic,Z-Wave,Rademacher Duofern,Signalduino,Fritz7590,ESPEasy,Tasmota,Robonect,Kameras,1-Wire,Modbus,Solar,Maranz,VU+,ulanzi tc001 mit awtrix light

laserrichi

ok... habe den Fehler jetzt selbst gefunden :

my ($inputa) = $_;  ist natürlich falsch
my ($inputa) = @_;  so scheint es zu funktionieren


dachte @ wäre für array und $ für einzelne
RaspberryPi 4 Bullseye,Homematic,Z-Wave,Rademacher Duofern,Signalduino,Fritz7590,ESPEasy,Tasmota,Robonect,Kameras,1-Wire,Modbus,Solar,Maranz,VU+,ulanzi tc001 mit awtrix light