Modbus newbie questions

Hi,

running 2.5.7, I’m having trouble to read my new Sungrow PV inverter via Modbus TCP, evolving into a number a basic questions.

First, what type would I need to use for reading values ?
My manufacturer’s document consist of two sections:
“Running information variable address definition (read-only register)” and
“Parameter setting address definition (holding register)”
Both cover values in the 5000 and 13000 range. I believe I need “input” for the former and “holding” for the latter ?

Second, my list of registers isn’t continuous. There’s say registers 5000-5036 but some addresses inbetween are reserved, say 5009+5010.
Can I read them nonetheless in one go, i.e. use a poller thing of length 37 ? Or do I need to create a separate thing for each continuous (sub)range ?

Third, getting closer, I see a number of data things come online while others remain offline either “bridge offline” or “Configuration error”, with no apparent pattern. Why ?

Finally, to get to the main point, I have some data things ONLINE, but they have no values and there is not a single entry in events.log showing they were ever retrieved, updated or whatsoever.

How can I debug that ? I already have

org.openhab.binding.modbus                                          x DEBUG
org.openhab.io.transport.modbus                                     x DEBUG

but see essentially nothing.

thanks
Markus

Mayyyybe. We can’t tell from that. A writable register is always holding (or coil for binary) - but nothing stops a designer deciding to treat any holding register as read-only and ignoring writes to it.

Sometimes the docs tell you what Modbus FC commands are to be used, this gives away the register type involved.

Mayyybe. Some designers let you read a block including undefined registers. Some will reject the request. Some will ignore the request (and you’ll see a timeout).

Always bear in mind the register address-or-number conundrum, where you may need to “take 1 off” depending on the designers convention.

It’s often worth having a play first with a tool like modbus-poll which allows you to discover what works and what doesn’t in a more interactive way than Thing editing.

Who can say. Your openhab.log should be telling you about gross config errors. But … how many Bridges have you defined? Generally one per TCP device, with as many pollers as you need, each with as many data Things as you need, all in a hierarchy.

But as you know, sharing problematic configurations is more helpful than guesswork.

1 Like

Sorry, of course:

bridge, pollers

1 bridge, 4 pollers (all online) and a thing for each datum

There’s a comment saying
Communication address = protocol address – 1. If data of address 5000 is to be inquired, the corresponding sending address data is 4999 (0x1387);,
so I would need to substract 1 from all poller start addresses and data things ?
I already tried that but no luck.
Main point is, I do not see any updates to PV* items or things in my events.log
Any suggestion for a proper Karaf debug setting ?

I used paperUI so here’s the Karaf output:

UID: modbus:tcp:f0352017
Type: modbus:tcp
Label: SH10RT
Status: ONLINE

No properties

Configuration parameters:
        timeBetweenTransactionsMillis : 60
        connectMaxTries : 3
        reconnectAfterMillis : 0
        port : 502
        timeBetweenReconnectMillis : 0
        host : 192.168.xxx.yyy
        connectTimeoutMillis : 10000
        id : 1
        enableDiscovery : false

No channels
openhab> smarthome:things show modbus:poller:947bd944
UID: modbus:poller:947bd944
Type: modbus:poller
Label: SH10RT-register-status
Status: ONLINE
Bridge: modbus:tcp:f0352017

No properties

Configuration parameters:
        maxTries : 3
        cacheMillis : 50
        start : 13000
        length : 44
        refresh : 500
        type : input

No channels
openhab> smarthome:things show modbus:poller:a2a1e059
UID: modbus:poller:a2a1e059
Type: modbus:poller
Label: SH10RT-register-runinfo
Status: ONLINE
Bridge: modbus:tcp:f0352017

No properties

Configuration parameters:
        maxTries : 3
        cacheMillis : 50
        start : 5000
        length : 37
        refresh : 5000
        type : input

No channels
openhab> smarthome:things show modbus:poller:86315202
UID: modbus:poller:86315202
Type: modbus:poller
Label: SH10RT-register-yield
Status: ONLINE
Bridge: modbus:tcp:f0352017

No properties

Configuration parameters:
        maxTries : 3
        cacheMillis : 50
        start : 6100
        length : 726
        refresh : 86400000
        type : input

No channels
openhab> smarthome:things show modbus:poller:1031e4f5
UID: modbus:poller:1031e4f5
Type: modbus:poller
Label: SH10RT-register-static
Status: ONLINE
Bridge: modbus:tcp:f0352017

No properties

Configuration parameters:
        maxTries : 3
        cacheMillis : 50
        start : 4950
        length : 49
        refresh : 500
        type : input

No channels

data things

openhab> smarthome:things show modbus:data:4e511e8b
UID: modbus:data:4e511e8b
Type: modbus:data
Label: PVthingnominalOutput
Status: ONLINE
Bridge: modbus:poller:a2a1e059

No properties

Configuration parameters:
        readValueType : uint16
        readTransform : default
        writeTransform : default
        readStart : 5001
        updateUnchangedValuesEveryMillis : 1000
        writeMultipleEvenWithSingleRegisterOrCoil : false
        writeMaxTries : 3

Channels:
        ID: number
        Label: Value as Number
        Type: modbus:number-type
        Description: Number item channel

        ID: switch
        Label: Value as Switch
        Type: modbus:switch-type
        Description: Switch item channel

openhab> smarthome:things show modbus:data:64c6b262
UID: modbus:data:64c6b262
Type: modbus:data
Label: PVthingbatteryAlarm
Status: OFFLINE (CONFIGURATION_ERROR): Thing modbus:data:64c6b262 readStart=13068, and readValueType=uint32 were specified even though the data thing is child of endpoint (that is, write-only)!
Bridge: modbus:tcp:f0352017

No properties

Configuration parameters:
        readValueType : uint32
        readTransform : default
        writeTransform : default
        readStart : 13068
        updateUnchangedValuesEveryMillis : 1000
        writeMultipleEvenWithSingleRegisterOrCoil : false
        writeMaxTries : 3

Channels:
        ID: number
        Label: Value as Number
        Type: modbus:number-type
        Description: Number item channel

        ID: switch
        Label: Value as Switch
        Type: modbus:switch-type
        Description: Switch item channel

        ID: contact
        Label: Value as Contact
        Type: modbus:contact-type
        Description: Contact item channel

        ID: dimmer
        Label: Value as Dimmer
        Type: modbus:dimmer-type
        Description: Dimmer item channel

items

Number:Power PVnominalOutput "nominalOutput [%.1f W]"                                   <energy>        (PV) { channel="modbus:data:4e511e8b:number" }
Number PVbatteryAlarm "batteryAlarm"                                                    <alarm>         (PV) { channel="modbus:data:64c6b262:number" }

If you can’t get anything to work, it’s much easier to work with a tool like modbus poll to get the basics sorted out, like IP address and wiring and register types and the take-off-1 business.

When you’ve got confidence in your parameters, is the time to move on to configuring openHAB. It demands accuracy and understanding of what you are doing, there is no discovery or auto-help here.

Your openhab.log should at least tell you
Modbus manager activated
so you know the binding is alive.

You’ll go mad if you don’t give your Things sensible names :wink:

It’s perfectly possible to configure from PaperUI, but you will find almost all examples are based on xxx.things files because they are easier to share and review for this binding.

You don’t seem to have any data Things, so your Items will not get updated. Debug logging will not help. Let’s get basics right first.
If you must debug log now, it’s in the docs

Most of your pollers should be active, but your device may be ignoring or rejecting polls. It certainly looks like you need to do the take-one-off address shift from the shared doc extract.

This poller will generate a config error -

Modbus packets are limited to 256 bytes by design
That’s just over 120 registers.
You cannot read 726 in one poll.

This Item and similar will not work properly -

Modbus binding does not support UoM, there are no units in the protocol.
It would be nice if a profile allowed for adapting with a user-supplied unit, one day.

I do just forgot to write them here. See updated config.

Yep, I did.

But that’s just an OH thing how to interpret. To the binding it’s a number, isn’t it ?

Ok thanks for your hints. I think I tried the -1 thing but will start with the poller tool as you suggested.

Too late already, will try tomorrow.

Yes indeed. But when you post “just a number” with no units to a Quantity Type the results can be unexpected.

I’ve no idea what happens should you send a Quantity Type command to a channel that doesn’t expect it.

I don’t seem to get anything. Tried offsets, tried via .things config, too (now I get at least some debug lines)
Tried the Modbus poll tool, it only ever tells me “04 Server Device Failure”.
Can you recommend any tool for basic testing outside OH ?

You haven’t shown us any information at all. What would you like to happen next?

If you’re at a loss, start simple. Try to read one data element that is fairly predictable - a model number or temperature.

If that is an exception code, it doesn’t tell us much beyond “error”.
If that is an exception code, it does confirm the remote device is responding to you, but it’s the device that is unhappy. (You might have asked it to do something it doesn’t like.)

Most use modbus poll.
I use simply modbus.
None of these tools are intuitive or easy, you need to understand what you’re trying to achieve at the protocol level.

That’s what I’m doing. TCP connect works, but I always get ‘slave device failure’. Also tried simply modbus tool, same result.
I’ve also tried various Python tools that claim to be able to read Sungrow inverters. While my device isn’t explicitly mentioned, the Py code matches my manual’s settings.
Communication Protocol of Residential Hybrid InverterV1.0.20.pdf (863.2 KB)

My current assumption is I must not try register say 13000 (as per doc) and function code 3 but register 313000? 113000? minus 1 ? It’s confusing. Some docs speak of 5-digit registers, some of 6-digit.

Then again I start believing that it does not work at all to locally query the modbus because of some security setting or similar, but that ain’t mentioned anywhere in the docs.

Sometimes I find it much easier to create a .things file with the bridge connection. (i never user PaperUI, specially not for modbus, as I find it more confusing than simple).
Then start off with one specific register, which you know (from the manufactor docs) what the output will be. I dont know your inverter, but I would assume at least one register should be rather simple.
Then work with this register only, untill you either manage to get the input, or work out everything possible reason to state, it doesnt work for modbus.
In short - one step at a time, and the most simple step only. Modbus is, (in my opinion) not easy, unless you have the knowledge like Rossko.

Yep, Modbus is at heart very simple, but manufacturers build different conventions on top and use different terms to describe it.

So, documents at last.
Starting simple -

You said you were using TCP
We can assume you have your IP, port and device ID correct … because you were getting responses.

The doc says -

Read-only register type supports the command code of 0x04.

It’s modbus, and modbus function 04 is ‘read input registers’
So we know what type to use.

Doc section 3.1 describes some read-only (and so we deduce input type) registers, and tells us register address 5000 is the device type. It further says it has 16-bit contents and we should see a value like hex D0A

Try it,
Set up one your tools to read one input register at address 5000, see if you get something like decimal 3338. Take care about whether your tool is using hex or decimal notation.

if you don’t, try address 4999 (on the basis that the doc may be talking register number and not strictly address)
Tell us what you do, tell us what you see.

EDIT - appendix 1.4 in the doc describes exactly this test. I note that it uses address hex 1387 for register 5000. hex 1387 is decimal 4999, so that conforms the doc is talking reg numbers.

I intentionally used reg 5001 so regardless of -1 or not, I should ‘hit’ a valid register.

Okay, don’t follow the advice.

Your immediate difficulty though is that simply modbus is not especially simple to use.
Look at the request sent, in the box.
00 03 00 00…
It’s broadcasting (id 0) an FC03 for address 0000
The target device rejects that.
This is not the FC04 that you are looking for.

Been a while since I’ve used simply modbus, from memory you have to tab around or press enter or something to accept the selection boxes, to get changes to stick.
You want that request to look more like
01 04 13 87 …

Playing around, I once got a reasonable response, but I could not reproduce it.
This one I think the request is right butthe answer again is not.

Using modbus poll tool, I see
Tx:000003-00 04 00 00 00 06 01 03 13 87 00 01
Rx:000004-00 04 00 00 00 06 01 83 04
which I think should be right, but the response again translates into 04 Server Device Failure

Any idea left other than to contact the vendor ?

I don’t know why, but all these requests begin with 00.
That’s the modbus device id byte.
id 00 is not valid
The protocol does however use it to tag a kind of “broadcast” command.
Few devices handle broadcasts correctly, nobody actually uses it.
I’m not surprised your device rejects it.
It should not even respond, really.

Summary; you need to send requests with a valid id. It’s probably 1.

I did mean it when I said you want your request to look like
01 04 13 87 etc.

EDIT - Ohhh wait this a simply modbus quirky display.
The 00 04 00 00 06 stuff is just TCP padding.
The proper modbus part in your last example is
01 03 13 87 …
which is much more like what we want. Id is good.
But it won’t work because you use FC03 and you want to use FC04

tried 3, 4
also freed all my OHs of modbus binding (assuming that it’s got to do with concurrent access)
but no difference

Well, when you’re ready show us your best effort at something you think should work, and the response. There is no point looking at stuff that isn’t going to work anyway.

Good point about ensuring you only have one service trying to talk to your device at a time.

Made some progress.
The main problem was that I accessed the WiFi IP which isn’t connected to the real modbus so it didn’t know the slave id. Now that I’m querying via Ethernet, I’m getting the responses we expected.

Tested right with my full set of ‘blindly’ setup OH things now I’m seeing just a couple of reads being returned.
Of those, only a single item keeps changing (the export power) which I think is correct, as the others are about the S/N and tracker voltages but it’s dark right now so they’re 0.
The data type items corresponding to register updates I see in modbus log are all set.
All others are NULL - is that correct, wouldn’t they need to be initialized at least once ?

2020-08-25 23:38:50.861 [DEBUG] [ernal.handler.ModbusDataThingHandler] - Thing modbus:data:c65e0fca channels updated: {modbus:data:c65e0fca:number=65535}. readValueType=uint16, readIndex=Optional[5014], readSubIndex(or 0)=0, extractIndex=14 -> numeric value 65535 and boolValue=true. Registers ModbusRegisterArrayImpl(00 64 00 01 00 d7 06 68 00 00 ff ff ff ff 01 ba 01 f9 00 00 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 00 00 09 34 09 36 09 47 00 07 00 0a 00 09 ff ff ff ff ff ff ff ff ff ff ff ff 01 fb 00 00 ff fc ff ff 03 e8 01 f3 ff ff) for request ModbusPollerThingHandler.ModbusPollerReadRequest@c4f4bc[slaveId=1,functionCode=READ_INPUT_REGISTERS,start=5000,length=37,maxTries=3]
2020-08-25 23:38:50.871 [DEBUG] [ernal.handler.ModbusDataThingHandler] - Thing modbus:data:cc5163d5 channels updated: {modbus:data:cc5163d5:number=0}. readValueType=uint16, readIndex=Optional[5011], readSubIndex(or 0)=0, extractIndex=11 -> numeric value 0 and boolValue=false. Registers ModbusRegisterArrayImpl(00 64 00 01 00 d7 06 68 00 00 ff ff ff ff 01 ba 01 f9 00 00 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 00 00 09 34 09 36 09 47 00 07 00 0a 00 09 ff ff ff ff ff ff ff ff ff ff ff ff 01 fb 00 00 ff fc ff ff 03 e8 01 f3 ff ff) for request ModbusPollerThingHandler.ModbusPollerReadRequest@c4f4bc[slaveId=1,functionCode=READ_INPUT_REGISTERS,start=5000,length=37,maxTries=3]
2020-08-25 23:38:50.881 [DEBUG] [ernal.handler.ModbusDataThingHandler] - Thing modbus:data:4e511e8b channels updated: {modbus:data:4e511e8b:number=1}. readValueType=uint16, readIndex=Optional[5001], readSubIndex(or 0)=0, extractIndex=1 -> numeric value 1 and boolValue=true. Registers ModbusRegisterArrayImpl(00 64 00 01 00 d7 06 68 00 00 ff ff ff ff 01 ba 01 f9 00 00 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 00 00 09 34 09 36 09 47 00 07 00 0a 00 09 ff ff ff ff ff ff ff ff ff ff ff ff 01 fb 00 00 ff fc ff ff 03 e8 01 f3 ff ff) for request ModbusPollerThingHandler.ModbusPollerReadRequest@c4f4bc[slaveId=1,functionCode=READ_INPUT_REGISTERS,start=5000,length=37,maxTries=3]
2020-08-25 23:38:50.893 [DEBUG] [ernal.handler.ModbusDataThingHandler] - Thing modbus:data:4ae285ca channels updated: {modbus:data:4ae285ca:number=65535}. readValueType=uint16, readIndex=Optional[5036], readSubIndex(or 0)=0, extractIndex=36 -> numeric value 65535 and boolValue=true. Registers ModbusRegisterArrayImpl(00 64 00 01 00 d7 06 68 00 00 ff ff ff ff 01 ba 01 f9 00 00 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 00 00 09 34 09 36 09 47 00 07 00 0a 00 09 ff ff ff ff ff ff ff ff ff ff ff ff 01 fb 00 00 ff fc ff ff 03 e8 01 f3 ff ff) for request ModbusPollerThingHandler.ModbusPollerReadRequest@c4f4bc[slaveId=1,functionCode=READ_INPUT_REGISTERS,start=5000,length=37,maxTries=3]
2020-08-25 23:38:50.905 [DEBUG] [ernal.handler.ModbusDataThingHandler] - Thing modbus:data:254ddcef channels updated: {modbus:data:254ddcef:number=0}. readValueType=uint16, readIndex=Optional[5013], readSubIndex(or 0)=0, extractIndex=13 -> numeric value 0 and boolValue=false. Registers ModbusRegisterArrayImpl(00 64 00 01 00 d7 06 68 00 00 ff ff ff ff 01 ba 01 f9 00 00 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 00 00 09 34 09 36 09 47 00 07 00 0a 00 09 ff ff ff ff ff ff ff ff ff ff ff ff 01 fb 00 00 ff fc ff ff 03 e8 01 f3 ff ff) for request ModbusPollerThingHandler.ModbusPollerReadRequest@c4f4bc[slaveId=1,functionCode=READ_INPUT_REGISTERS,start=5000,length=37,maxTries=3]
2020-08-25 23:38:50.915 [DEBUG] [ernal.handler.ModbusDataThingHandler] - Thing modbus:data:cbb85eaf channels updated: {modbus:data:cbb85eaf:number=0}. readValueType=uint16, readIndex=Optional[5012], readSubIndex(or 0)=0, extractIndex=12 -> numeric value 0 and boolValue=false. Registers ModbusRegisterArrayImpl(00 64 00 01 00 d7 06 68 00 00 ff ff ff ff 01 ba 01 f9 00 00 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 00 00 09 34 09 36 09 47 00 07 00 0a 00 09 ff ff ff ff ff ff ff ff ff ff ff ff 01 fb 00 00 ff fc ff ff 03 e8 01 f3 ff ff) for request ModbusPollerThingHandler.ModbusPollerReadRequest@c4f4bc[slaveId=1,functionCode=READ_INPUT_REGISTERS,start=5000,length=37,maxTries=3]
2020-08-25 23:38:50.982 [DEBUG] [bus.handler.ModbusPollerThingHandler] - Thing modbus:poller:947bd944 received response PollResult(result=AsyncModbusReadResult(request = ModbusPollerThingHandler.ModbusPollerReadRequest@17c1847[slaveId=1,functionCode=READ_INPUT_REGISTERS,start=13000,length=44,maxTries=3], registers = ModbusRegisterArrayImpl(00 0c 00 f7 06 e8 00 00 00 52 03 74 00 00 01 fa 00 00 00 01 00 00 00 58 01 8a 00 00 04 d5 00 00 00 4d 01 ea 00 00 0f 6b 00 10 01 fb 02 55 03 e8 01 18 00 36 01 01 00 00 01 e4 ff ff 00 07 00 0a 00 09 01 fb 00 00 00 26 01 9c 00 00 26 48 00 58 01 8e 00 00 00 ff 00 00)))
2020-08-25 23:38:50.991 [DEBUG] [ernal.handler.ModbusDataThingHandler] - Thing modbus:data:c41cd3c9 channels updated: {modbus:data:c41cd3c9:number=247}. readValueType=uint16, readIndex=Optional[13001], readSubIndex(or 0)=0, extractIndex=1 -> numeric value 247 and boolValue=true. Registers ModbusRegisterArrayImpl(00 0c 00 f7 06 e8 00 00 00 52 03 74 00 00 01 fa 00 00 00 01 00 00 00 58 01 8a 00 00 04 d5 00 00 00 4d 01 ea 00 00 0f 6b 00 10 01 fb 02 55 03 e8 01 18 00 36 01 01 00 00 01 e4 ff ff 00 07 00 0a 00 09 01 fb 00 00 00 26 01 9c 00 00 26 48 00 58 01 8e 00 00 00 ff 00 00) for request ModbusPollerThingHandler.ModbusPollerReadRequest@17c1847[slaveId=1,functionCode=READ_INPUT_REGISTERS,start=13000,length=44,maxTries=3]
2020-08-25 23:38:51.000 [DEBUG] [ernal.handler.ModbusDataThingHandler] - Thing modbus:data:0a446925 channels updated: {modbus:data:0a446925:number=1}. readValueType=int32, readIndex=Optional[13008], readSubIndex(or 0)=0, extractIndex=8 -> numeric value 1 and boolValue=true. Registers ModbusRegisterArrayImpl(00 0c 00 f7 06 e8 00 00 00 52 03 74 00 00 01 fa 00 00 00 01 00 00 00 58 01 8a 00 00 04 d5 00 00 00 4d 01 ea 00 00 0f 6b 00 10 01 fb 02 55 03 e8 01 18 00 36 01 01 00 00 01 e4 ff ff 00 07 00 0a 00 09 01 fb 00 00 00 26 01 9c 00 00 26 48 00 58 01 8e 00 00 00 ff 00 00) for request ModbusPollerThingHandler.ModbusPollerReadRequest@17c1847[slaveId=1,functionCode=READ_INPUT_REGISTERS,start=13000,length=44,maxTries=3]
2020-08-25 23:38:51.070 [DEBUG] [bus.handler.ModbusPollerThingHandler] - Thing modbus:poller:1031e4f5 received response PollResult(result=AsyncModbusReadResult(request = ModbusPollerThingHandler.ModbusPollerReadRequest@62098a[slaveId=1,functionCode=READ_INPUT_REGISTERS,start=4950,length=49,maxTries=3], registers = ModbusRegisterArrayImpl(41 42 11 00 01 00 41 52 4d 5f 53 41 50 50 48 49 52 45 2d 48 5f 56 31 31 5f 56 30 31 5f 41 00 00 00 00 00 00 4d 44 53 50 5f 53 41 50 50 48 49 52 45 2d 48 5f 56 31 31 5f 56 30 31 5f 41 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 41 32 30 30 36 32 30 32 33 33 30 00 00 00 00 00 00 00 00 00)))
2020-08-25 23:38:51.096 [DEBUG] [ernal.handler.ModbusDataThingHandler] - Thing modbus:data:3b7a4827 channels updated: {modbus:data:3b7a4827:string=12336}. readValueType=uint16, readIndex=Optional[4990], readSubIndex(or 0)=0, extractIndex=40 -> numeric value 12336 and boolValue=true. Registers ModbusRegisterArrayImpl(41 42 11 00 01 00 41 52 4d 5f 53 41 50 50 48 49 52 45 2d 48 5f 56 31 31 5f 56 30 31 5f 41 00 00 00 00 00 00 4d 44 53 50 5f 53 41 50 50 48 49 52 45 2d 48 5f 56 31 31 5f 56 30 31 5f 41 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 41 32 30 30 36 32 30 32 33 33 30 00 00 00 00 00 00 00 00 00) for request ModbusPollerThingHandler.ModbusPollerReadRequest@62098a[slaveId=1,functionCode=READ_INPUT_REGISTERS,start=4950,length=49,maxTries=3]

That’s good. Sneaky that it responded to a modbus poll, rather than just staying silent.

Items are NULL until they’re not NULL. What do your Things and Items look like now? there were errors before. Which ones don’t work?

Now that I corrected what was wrongly mapped, all things are online and items get updated on modbus readout. When the channel gets an update.
I’m missing a couple of popular values such as battery SOC but I guess only the vendor knows when that one gets updated.