openhab / openhab1-addons

Add-ons for openHAB 1.x
Eclipse Public License 2.0
3.43k stars 1.7k forks source link

[modbus-binding] issues with 'length' parameter #4931

Open Pirx99 opened 7 years ago

Pirx99 commented 7 years ago

When using the following connection definition in modbus.cfg and accessing "sma2:0" the returned value is wrong:

tcp.sma2.connection=192.168.178.3:502 tcp.sma2.type=input tcp.sma2.id=3 tcp.sma2.start=30201 tcp.sma2.length=2 tcp.sma2.valuetype=uint32

When I change tcp.sma2.length to "4" the returned value is correct. However, according to documentation "2" should be enough.

Am I right or wrong?

Your Environment

OHA2 build 660 modbus 1.9.0

ssalonen commented 7 years ago

Hi, thanks for reporting this.

Could please elaborate what do you mean by "wrong value"? What kind of item configuration you have?

Depending on the item configuration, the length of 2 might not be enough.

Best Sami

ssalonen commented 7 years ago

Can you try to reproduce the issue with diagslave and/or pollmb.py?

As far as I can tell the item definition with "sma2:0" should return same value with length 2 and 4.

Pirx99 commented 7 years ago

This is my item configuration: _Number SMAStatus "Status [%d]" { modbus="sma2:0" }

Wrong value means, that I get a 256 instead of 307. It's curious! RMMS shows the values correctly..... It was more or less a coincident to find out that I have to extend the length. What do you mean by reproducing it with diagslave?

ssalonen commented 7 years ago

So you get different value when you change length to 4? This indeed curious.

You could try to read the registers using pollmb.py and see if you get the same result as with the binding. In pollmb you have possibility read 32 bit integers directly.

With diagslave you can setup a tcp modbus server (slave). You can use pollmb.py to write data to the registers, by default they are all zero. If the issue is in the binding, you should be able to witness the same issue with the test slave.

Making these two tests would be much appreciated

Best Sami

ssalonen commented 7 years ago

Also : I assume that you did not send any commands to test item. Those would try to write to modbus and the binding has limitations with 32 bit valuetypes on write (see wiki)

Edit : verbose logs with different settings would be muchappreciate d, I believe you can see the responses there as well.

Pirx99 commented 7 years ago

No. I'm only reading. Just polling the modbus device and displaying the values. Will try out pollmb.py tomorrow morning.

Pirx99 commented 7 years ago

The results from pollmb.py are even more curious :-) Or my brain is too small to understand it. Look at these two runs below. I'm reading the same register 30201 as with the binding

--- 1st run with q=2

python pollmb.py -h 192.168.178.3 -p 502 -u3 -f4 -a30201 -q2 Contacting Modbus host at 192.168.178.3 port 502 timeout 60.0 sec. Sending Modbus function: 4, addr: 30201, qty: 2, data: 0000 for 1 polls at 1 msec 1: Reply was: function: 4, data: 000001

---- 2nd run with q=4

python pollmb.py -h 192.168.178.3 -p 502 -u3 -f4 -a30201 -q4 Contacting Modbus host at 192.168.178.3 port 502 timeout 60.0 sec. Sending Modbus function: 4, addr: 30201, qty: 4, data: 0000 for 1 polls at 1 msec 1: Reply was: function: 4, data: 00000133000027


The correct result is 0x00000133 = decimal 307. It's what I'm expecting (look at my comment from yesterday about wrong and right) and what RMMS sees. Can you tell me what 'q' really means? Is it a byte or one and half byte or what ? :-)

ssalonen commented 7 years ago

Thanks for trying this out.

I believe q has the same interpretation as in openhab : it is the number of registers to read.

Using this online converter the numbers match what the binding also gives. With q=2 we get 256, and with q=4 we get 307.

I think 000001 is shorthand for 0x00000100.

The result is really odd, I think even the typical "off by one" error with the index does not explain the result...

Best Sami

Pirx99 commented 7 years ago

Yes, it's odd. So with q=2 (or length=2) either the slave is sending only 6 bytes or the master is pulling only 6 bytes instead of 8 bytes . One of both are doing a wrong job. However, there is a workaround and I'm leaving it for now. I'd like to spend more time for things I haven't solved or learned so far.

Thanks & Best Maciej

ssalonen commented 7 years ago

You are actually right, it makes no sense that "000001 would be shorthand for 0x00000100".

For future records, tried out pollmb.py against test server (diagslave):

$ ./pollmb.py -h localhost -p 55522 -u3 -f4 -a30201 -q4

Contacting Modbus host at localhost port 55522 timeout 60.0 sec.
Sending Modbus function: 4, addr: 30201, qty: 4, data: 0000 for 1 polls at 1 msec
1: Reply was: function: 4, data: 0000000000000000

$ ./pollmb.py -h localhost -p 55522 -u3 -f4 -a30201 -q2

Contacting Modbus host at localhost port 55522 timeout 60.0 sec.
Sending Modbus function: 4, addr: 30201, qty: 2, data: 0000 for 1 polls at 1 msec
1: Reply was: function: 4, data: 00000000

One can see that with q=2, we data is length of 8 characters, not six like with your slave.

Since the problem can be reproduced with a third party software (pollmb.py), I fear the issue is on the slave end. You might be right about master not polling enough bits also, would have to dig in deeper to confirm that.

Agree that it makes sense to close this as workaround exists, and seems like a esoteric master-slave issue.

Best, Sami

cybergreen2 commented 7 years ago

I have the same problem, like mentioned on the top of the issue. I also polling an SMA Device with my OH2 backend and installed modbus addon. It seems, that the problem isn't the SMA device (modbus slave), since the received response include the right value.

Following modbus configuratian I am using:

tcp.wr1_gesamtertrag.connection=192.168.30.1:502:60:0:100:0:0
tcp.wr1_gesamtertrag.type=input
tcp.wr1_gesamtertrag.id=3
tcp.wr1_gesamtertrag.start=30531
tcp.wr1_gesamtertrag.length=2
tcp.wr1_gesamtertrag.valuetype=uint32

Inside the received TCP modbus response the right value 0x0fb0 (4016 decimal) is include, but on the OH2 GUI the value 3840 (0x0f00) is displayed. It seem, that the last eight bits are irgnored during the "decoding". see attached TCP modbus dump: tcp_modbus_dump.zip OH2 output: oh2_output

OH2 configuration: Number PV_WR1_Gesamtertrag "G [%d]" { modbus="wr1_gesamtertrag:0" }

environment: OH2.0.0.b5 with binding-modbus1 - 1.9.0.b5

I think the issue should be reopend, since there is a problem inside the modbus add-on and not on the slave side.

watou commented 7 years ago

Does the length=4 workaround not work for you?

cybergreen2 commented 7 years ago

Yes, the workaround is running fine. But the problem is not the slave (SMA device), the mistake is inside the OH modbus add-on. This should be fixed, I think. Somewhere inside the python scripts also the last 8 bits are not forwarded, whyever. The pollmb.py output from Pirx99 show this. The 4-length-output ist also shortened by the last 8 bits.

The modbus response TCP packet from the SMA device, within my above attachment, looks well according to the MODBUS APPLICATION PROTOCOL SPECIFICATION v1.1b3 section 6.4 on page 16.

Pirx99 commented 7 years ago

You're misinterpreting my results. pollmb.py has nothing to do with OpenHAB and I had to apply the same workaround to get correct results. So my feeling was, that the failure is rather on the slave side. Furthermore it happens with SMA only, at least at my home

cybergreen2 commented 7 years ago

I think I am not misinterpreting your results, since I know Openhab isn't equal pollmb.my. I had had some other presumptions.

After somemore investigations, I identified the difference between the SMA devices and others. In the above attached tcp dump you can see, that the response of the Modbus slave is segementated in 2 segments. Inside the first segment you can find the first 3 bytes (00 00 0f) of the polled two modbus registers. The 4th (and last) byte (b0) was send separatly. The modbus master only interpret the first TCP segment, the second isn't been observed.

The segmentation of this short TCP payload is absolutely unnecessary, of course. The transmitted modbus data are a lot of smaller than the possible and announced TCP maximum segment size. On the other hand, the TCP protocol implemtation inside Openhab und pollmb.py should reunion the receiving TCP segements correctly before the payload is forwarded to the modbus layer at the stack. At the moment, I don't know, if the handling of more than one TCP segement is accurate implemented in this protocol stack. This should be more investigated. I know the TCP segementation / IP fragmentation on the transmitting path is really unlikely, but possible and permitted.

In this case, I think the modbus implementation is on the SMA device isn't done well. So I will call SMA und describe our observations.

Somebody knows, if the a TCP segmentation of modbus payloads is forbidden?

Pirx99 commented 7 years ago

Interesting! It explains the behavior i experienced as well. Just one hint: at SMA they are using RMMS to test the Modbus communications with the inverters. I obeserved the same issue with RMMS when you limit the read to one register only. So test it before approaching the SMA support.
Having said that, I can't imagine that the way SMA is sending the TCP packages is correct, but I'm not an expert on it. A good guy to talk with at SMA support is Kai Schmidt. You can mention that there is another customer which has the same issue! Good luck and tell us the results!

cybergreen2 commented 7 years ago

Last week, I opend a ticket with a detailed discription of my/our observations/investigations on the SMA website. Today, I had talked a lot of with different SMA support guys. In short: This (modbus) issue is to specific for the service hotline and a forewarding to the engineering/development department isn't possible. No process is exitisting for such kind of customer issues/queries. Also they said, their modbus implementation operates correctly, since the value inside RMMS will show accurate. Many customers use the modbus interface and don't have any trouble. Therefore, no debugging is required on a part of SMA.

@Pirx99: Unfortunately, I can't reporduce your obersavations with RMMS during the reading of only one register at the application. With wireshark I saw two TCP segments, of course.

I think the implementation of RMMS considered the anticipated length of the response and wait for the second TCP segment with the last byte an modbus layer before displaying the transmitted value. Does the modbus openhab add-on consider the anticipated length of the response? Perhaps, this feature could resolve this issue... on the other side the workaround works well for me.

It's unsatisfactory to detect an issue and SMA doesn't care about it!!!!

ssalonen commented 7 years ago

It does consider the length, see here.

But I'm wondering whether readFully should be used instead of read... the latter is not guaranteed to read all the requested bytes according to the javadoc...

I made a test version with readFully (code here), could you please try with this version?

org.openhab.binding.modbus-1.9.0-readfully-SNAPSHOT.zip

Best Sami

cybergreen2 commented 7 years ago

I tested your "special" version. Unfortunately, the ouptut is any more not correct. The last byte isn't considered. Can you insert some System.out.println lines or degging outputs inside ModbusResponse readResponse(), particular to evalute the content of buffer and res, please?

ssalonen commented 7 years ago

Hi

Perhaps it would be faster for you to fork the code since you can test it directly with the real slave?

Btw, did we have any third party software that would read the data correctly?

Let me know how it goes!

Best Sami

cybergreen2 commented 7 years ago

Yes, we have... Radzio! Modbus Master Simulator and Simply Modbus TCP Client At the weekend I will test again.

Pirx99 commented 7 years ago

Hi all, the workaround described above (to simply read additional 2 bytes) seems to not work when writing to the device.

I have the following modbus definition:

# SMA: 40915  Dauerhafte Wirkleistungsbegrenzung, in W
tcp.sma42.connection=192.168.178.3:502
tcp.sma42.type=holding
tcp.sma42.id=3
tcp.sma42.start=40915
tcp.sma42.length=4
tcp.sma42.valuetype=uint32

and the corresponding item definition is: Number SMA_WL_Begrenzung "Wirkleistungsbegrenzung [%d W]" <energy> { modbus="sma42:0" }

When reading everything is correct, but when I use sendCMD the following message appears:

21:56:18.380 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'SMA_WL_Begrenzung' received command 7500
21:56:18.582 [ERROR] [.binding.modbus.internal.ModbusSlave] - ModbusSlave (sma42): error when executing write request (net.wimpi.modbus.msg.WriteSingleRegisterRequest@84ad048): Error Code = 0

What can I do?

ssalonen commented 7 years ago

@pirx99 I suggest you try to reproduce the issue with another tool, say pollmb.py

See this for more details: https://github.com/openhab/openhab1-addons/wiki/Modbus-Binding#writing-data

Error you are Receiving seems to come from the slave directly (modbus exception response) although I'm a bit surprised by error code 0.

You can also try verbose logging (see wiki for details) to see if you get more information.

Best Sami

Pirx99 commented 7 years ago

Hi Sami,

just done some queries using pollmb.py and it confuses me a lot. As mentioned above I'm accessing the register 40915 which is a 32-bit unsigned integer. I tried three different lengths (4, 3, and 2). The correct value should be Hex 00001B58 or Decimal 7000. Look at the results of pollmb.py

Maciejs-iMac:pollmb Maciej$ python pollmb.py -h 192.168.178.3 -p 502 -u3 -f4 -a40915 -q4

Contacting Modbus host at 192.168.178.3 port 502 timeout 60.0 sec.
Sending Modbus function: 4, addr: 40915, qty: 4, data: 0000 for 1 polls at 1 msec
1: Reply was: function: 4, data: 00001b58ffffff
Maciejs-iMac:pollmb Maciej$ python pollmb.py -h 192.168.178.3 -p 502 -u3 -f4 -a40915 -q3

Contacting Modbus host at 192.168.178.3 port 502 timeout 60.0 sec.
Sending Modbus function: 4, addr: 40915, qty: 3, data: 0000 for 1 polls at 1 msec
1: Reply was: function: 4, data: 00001b58ff
Maciejs-iMac:pollmb Maciej$ python pollmb.py -h 192.168.178.3 -p 502 -u3 -f4 -a40915 -q2

Contacting Modbus host at 192.168.178.3 port 502 timeout 60.0 sec.
Sending Modbus function: 4, addr: 40915, qty: 2, data: 0000 for 1 polls at 1 msec
1: Reply was: function: 4, data: 00001b

What I don't understand is why pollmb.py is giving me 7 bytes back, when ask for 8 bytes (-q4) I get 5 bytes with -q3 and 3 bytes with -q2. To my understanding all this is wrong. One can see the correct value in there (00001b58) but not as an isolated 'string'

RMMS is struggling as well. When I try to read the same with length=2 I get an error. Only the length=4 works.

Your thoughts?

ssalonen commented 7 years ago

Hi!

Actually, what I meant that try to write data with pollmb, and see if you get an exception response from the slave.

(write value 7500 to register 40915)

Actually, now that I look at your definition I hope you understand that writing commands to 32bits (two registers) is not implemented. I've tried to document this limitation in the wiki. See also the related issue #428 and discussion in community forums.

With the experimental version (see PR https://github.com/openhab/openhab1-addons/pull/5098 & community discussion) it should be possible to workaround this if you use javascript transformation to extract high 16bits, and low 16 bits from the command, and write those to separate registers. The binding would then make two write requests per each "decimal command" in openhab. This is truly a workaround in a way since there is a split second where the number is written only "partially", slave seeing this value. Depends on your use case if this is an issue.

I guess it might be also possible that slave actively blocks single register writes -- but this you can verify with pollmb. If you get the error with that too, the workaround above with the experimental version would not work for you.

--

Not getting all bits on read is something we noticed already earlier on this thread and seem to be something specific to this slave, or something in implementation that both the binding and pollmb.py suffers from.

RMMS is struggling as well. When I try to read the same with length=2 I get an error. Only the length=4 works.

This is interesting :o I though RMMS worked previously ok? In ref to your comments before

Could you elaborate what do you mean by "struggling"? :)

Best, Sami

Pirx99 commented 7 years ago

No chance to write anything to the modbus device with pollmb. What ever I tried I always got a reply "function: 0". Seems to be the same "0" I received from the binding.

Thanks for the hint with the limitations. I was not aware! I guess, it doesn't make sense to try the workaround as long as I cannot successfully write anything using pollmb.py. First, I will contact the vendor support for that device tomorrow (which is a SMA inverter).

:-) "struggling" means "fighting to deal with something"..... I tried to read the register 40915 with RMMS again. Now, it works with Length=10, but not with 4 and not with 2. The Error counter is running high. It's a mess ... I have the feeling that the Modbus implementation at SMA is faulty. Sometimes the RMMS can read a values, sometimes not... I have another Modbus device and it is working perfectly.

ssalonen commented 7 years ago

@pirx99 I kind of agree to your conclusion... The error code 0 is not even in the spec.

It was interesting the tcp segment investigation in this thread but not sure if that is the full story. Since the readfully implementation did not fix it seems that wrong data is received (not just missing) on the wire I'm afraid.

Having now found multiple modbus master implementations with issues with this slave, it seems likely that it has unconventional or buggy modbus implementation.

Is there anything to try out still or should we close this (as unresolved)?

Best Sami

Pirx99 commented 7 years ago

@Sami,
no, we shouldn't close it. Today I have opened a support ticket at SMA, which is the vendor of the problematic modbus slave. I shared a link to this thread as well. The guy I'm talking to will try to assess the issue with another tool. It will take some days for the next update, so be patient.

Kind regards, Maciej

ssalonen commented 6 years ago

@Pirx99 , any update on this?

frrr1 commented 6 years ago

Hi all,

I can confirm that I have exactly the same symptoms with my STP5000TL20 SMA inverter. Regarding the thread-history I would guess that RMMS is compensating the "erroneous" behaviour of the SMA inverter. I just tested reading the register 30537 (daily yield kWh) using the Modbus Poll Tool (q=2). It shows 30537=000000 and 30538=000003 (3 being the correct decimal value). If SMA is reading this thread I would also kindly ask you to investigate the described problem on your side.

Also see https://community.openhab.org/t/modbus-openhab2-binding-available-for-alpha-testing/27657/256 for my corresponding post at openhab community.

Thanks all, frrr

Pirx99 commented 6 years ago

Hi frrr1, unfortunately SMA don't read it. This is the work around for your issue:

# SMA: 30529 ff. sums (read 8 continues values)
# +0: 30529 Total yield Wh
# +1: 30531 Total yield kWh
# +2: 30533 Total yield MWh
# +3: 30535 Daily yield Wh
# +4: 30537 Daily yield kWh
# +5: 30539 Daily yield MWh
# +6: 30541 Operating time s
# +7: 30543 Feed-in time s
tcp.sma3.connection=192.168.178.3:502
tcp.sma3.type=input
tcp.sma3.id=3
tcp.sma3.start=30529
tcp.sma3.length=16
tcp.sma3.valuetype=uint32

and this is one the items : Number SMA_daily_yield "Daily yield [%d kWh]" { modbus="sma3:4" }

Because the resolution is easy I stopped to chase SMA.

Hope that helps! Pirx

Pinksheepxx commented 5 years ago

Hello,

I am trying to get SMA Tripower 5000TL yield values to openhabian by using speedwire/tcp modbus connection.

Otherwise everything seems to work as it should, but now I have same problem as in this topic. I do get values to sitemap, but those are not correct. RMMS do get values correct, but as described earlier, even it has some weird problems. Some starting address and length combination do not work.

I have openhab 2.4.0 and new modbus binding.

Is there a way to get values right with new modbus binding?

ssalonen commented 5 years ago

@pinksheepx this is wrong place to have this discussion as you are talking about the openHAB2 binding.

Could you please open new community thread and let's continue the discussion there?