tjhowse / modbus4mqtt

Modbus TCP <-> MQTT glue. YAML configuration. Robust.
Other
75 stars 33 forks source link

Modbus TCP connection handling #21

Open jmkelly opened 3 years ago

jmkelly commented 3 years ago

I've noticed that when I initially connect modbus4mqtt on my SG-5K-D, I get a readout for all the registers, and unless I've got a register in there that is wrong, no errors. As it keeps running though, I'm only getting readouts on a few registers that regularly update and lots of exceptions on less frequently changing registers.

I was wondering if this could be something to do with a single tcp connection staying alive for the whole time that modbus5mqtt is running? I've looked at the code, and I'm not all that familiar with python, but am I correct in assuming that once a tcp connection is made to the inverter, it is kept open? If this is the case, then I was wondering what your thoughts on tearing down the connection and then re establishing it each tcp call to the inverter?

jmkelly commented 3 years ago

I did some more reading. From what I can tell, the connection is being established, then isn't explicitly closed.

In the SunGrowModbus library at https://github.com/rpvelloso/Sungrow-Modbus/blob/59130209e5e77dd105cd17c012c6a83f3c864bb7/SungrowModbusTcpClient/SungrowModbusTcpClient.py#L48 the existing connection is closed when a new connection is made.

in the Modbus libary, the connection isn't shutdown unless you call it, or there is a connection error (from my quick scan). https://github.com/riptideio/pymodbus/blob/efb90fb05882d606933a97435dd37ae87ead5449/pymodbus/client/sync.py#L202

I'd be interested in spiking out and testing connect, read data and close the connection explicitly, but I'm struggling to find exactly where the open / read / close would sit. And also what implications of doing this may have....

tjhowse commented 3 years ago

Correct - We start up a TCP connection when the service starts and it remains open as long as it can. If you wanted to experiment with opening and closing the connection with each poll, a good place for that would be in modbus_interface.poll()

https://github.com/tjhowse/modbus4mqtt/blob/master/modbus4mqtt/modbus_interface.py#L62

And then remove the connect code here: https://github.com/tjhowse/modbus4mqtt/blob/master/modbus4mqtt/modbus4mqtt.py#L41

However this isn't the intended use of a modbus interface. It's expecting to have a long-running connections open. Reconnecting on every poll would result in a lot of overhead. I would love to understand the real reason for the errors before attempting a fix. I've connected directly to my SH5k-20 via ethernet rather than using the wifi-to-rs485 solarinfo dongle. I still get errors, but not enough to affect operation. I suspect part of the reason for my errors is the fact I'm running both pvstats and modbus4mqtt, and they're giving the inverter too much to think about.

Maybe there's some kind of keepalive signal the Sungrow inverter is expecting? Like a heartbeat signal? I'd like to look at a packet capture of a "proper" modbus TCP connection to see whether the interface is expecting something like that.

I strongly suspect that the Sungrow implementation of modbus is only "inspired" by the modbus spec, not actually modbus-compliant. There may be some interface settings that can be tweaked on our side to make the connections happier.

I have a task on the backlog to report multiple values in one message to MQTT via a JSON message: #9 Once this is implemented I can retire pvstats from my system and work on getting the error rate down. However my system is different to most in two ways: A) I'm not using wifi and, B) I've blocked the inverter from talking to the internet.

jmkelly commented 3 years ago

thanks for the information, I'm a total noob to modbus, so its good to get more perspective. Any suggestions on how to do the packet capture? I'm running over wifi and connected to internet, so I'm thinking i could pick up the outgoing traffic to iSolarCloud if I can intercept the traffic going via my router (google wifi).

Looks something like https://geeknizer.com/capture-sniff-wifi-traffic/ in combination with wireshark may do the trick, when I get a chance, I'll try to set it up and get something happening.

If you have any easier suggestions though, I'm all ears.

tjhowse commented 3 years ago

When I've been sniffing the connection to my inverter I used a packet squirrel, however they only work on ethernet connections - not wifi.

In any case the link from domestic inverters to the sungrow cloud services is a pseudo-encrypted MQTT link, not modbus. We'd need a reference implementation of a sungrow-endorsed modbus interface to one of their devices to classify exactly what connection parameters keep the connection happy. At the moment modbus4mqtt assumes that it doesn't need to do anything special to the connection to keep it connected. I know a few companies across the world are working on custom integrations to home inverters, but I'm not aware of anything specific to sungrow yet.

tjhowse commented 3 years ago

I've just remembered I had this doc floating around. I have it referenced in another project, page 89 is most interesting: https://c.tjhowse.com/misc/SolarInfo%20Logger%20User%20Manual.pdf

jmkelly commented 3 years ago

There’s some great info in there, but I can’t join the dots. What are you thinking?

On Sat, 2 Jan 2021 at 3:54 pm, Travis Howse notifications@github.com wrote:

I've just remembered I had this doc floating around. I have it referenced in another project, page 89 is most interesting: https://c.tjhowse.com/misc/SolarInfo%20Logger%20User%20Manual.pdf

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/tjhowse/modbus4mqtt/issues/21#issuecomment-753431531, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAA6I6SGR6K6MRGC7KAZGIDSX2RHJANCNFSM4VNY6VCA .

tjhowse commented 3 years ago

Nothing specific - just adding some potentially useful context.

icypete commented 3 years ago

I'm wondering if a middle ground solution would be to set a reconnect period, after which the connection is closed and reconnected. This would be independent of the polling period. For example we can poll every 5 seconds, but every (say) 10min the TCP connection is closed and re-established.