Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ModBus RTU to TCP gateway #9586

Closed
TheChatty opened this issue Oct 20, 2020 · 251 comments · Fixed by #16075, #16078 or #16092
Closed

ModBus RTU to TCP gateway #9586

TheChatty opened this issue Oct 20, 2020 · 251 comments · Fixed by #16075, #16078 or #16092
Labels
feature request (devs?) Action - awaiting response from developers requested feature (hold over) Result - Feature that will not be added soon (out of scope)

Comments

@TheChatty
Copy link
Contributor

TheChatty commented Oct 20, 2020

Have you looked for this feature in other issues and in the docs?
I did. It's not implemented yet. Here is an existing gateway in C or stripped down in python. This is the basic idea behind a RTU/TCP gateway.

Is your feature request related to a problem? Please describe.
I want to be able to poll certain registers from my modbus device regularly via MQTT and be able to configure it via a TCP-based Windows app.

Describe the solution you'd like
Implement a RTU/TCP gateway in Tasmota which allows concurrent access to a modbus device on Tx/Rx.

Describe alternatives you've considered
Alternatively I can either connect Tasmota for MQTT-based access or my PC directly for TCP-based access.

Additional context
This gateway is a litte bit more than a simple serial TCP bridge in the sense that it adds and also strips a few bytes from each request/response.

(Please, remember to close the issue when the problem has been addressed)

@s-hadinger
Copy link
Collaborator

Tasmota always prefers MQTT protocol wherever it's possible. We strongly suggest to use the Mqtt gateway instead.

@TheChatty
Copy link
Contributor Author

TheChatty commented Oct 20, 2020

At least I need Tasmota to act as TCP gateway because my heating regulator Trovis 5573 can only be configured using a software called Trovis View which only supports communication via TCP. My idea is to enhance your code with an option "TCP_BRIDGE_MODBUS" for according byte mangling (see python solution linked in description).

@ascillato2 ascillato2 added the feature request (devs?) Action - awaiting response from developers label Oct 21, 2020
@Jason2866
Copy link
Collaborator

Jason2866 commented Oct 21, 2020

Tasmota already has a TCP gateway. See config example used for the ZbBridge for connecting with HomeAssistant (ZHA)
https://zigbee.blakadder.com/Sonoff_ZBBridge.html
Command TCPStart <Port>
Sorry a implementation for all different special use cases for a TCP bridge will not be done

@TheChatty
Copy link
Contributor Author

I linked to Tasmota TCP bridge already in the first post. But I need the gateway to mangle the bits a little.

Another option would be to implement the gateway in the SML interface. The meter is already defined (baudrate, protocol, pins, etc) and thus the gateway only needs to insert its TCP commands along the other commands from the MQTT/console stream.

Since a meter can only be connected to one host it would be great if continous meter value logging could be combined with (rare) meter configuration stuff (in my case with a TCP-based Windows app, a TCP-based smartphone app is available as well).

@Jason2866
Copy link
Collaborator

The use case is very specific. So it will be probably not done from the main contributors. Maybe you are lucky and someone has the need too and provides a PR.
With the solution as it is now, the needed manipulations can be done on receiver side with a little (Python?) tool and providing the data to your Application.

@ascillato2
Copy link
Collaborator

Closing this request as there is no active development on this. Please, ask to reopen if you want to work on this. Thanks.

@ascillato2 ascillato2 added the requested feature (hold over) Result - Feature that will not be added soon (out of scope) label Nov 9, 2020
@jeroenst
Copy link
Contributor

jeroenst commented Jul 20, 2022

@TheChatty Can you try this?

I have added the modbustcpstart en modbustcpconnect functions.

I also removed the (u)int8 option for modbus send command, because modbus registers are always 16 bits.

The data received from the tcp client is not checked btw, it's just send to the modbus client.

I will also write a small tcpclient to test this added feature.

https://github.com/jeroenst/Tasmota/tree/ModbusTCP

@TheChatty
Copy link
Contributor Author

I flashed the .gz you provided but are unable to select "ModBr .." in Configuration? It's not listed.

@jeroenst
Copy link
Contributor

I will look at it tomorrow. Otherwise compile it from my branch.

@TheChatty
Copy link
Contributor Author

@Jason2866: A ModBus TCP gateway is a widely requested feature I'd say. Enhancing driver 41 or 63 is not really important. The code impact is rather small, the usage gain is much bigger. If implemented in driver 41 TCP/RTU protocol conversion could be handled by a new option for instance.

@TheChatty
Copy link
Contributor Author

TheChatty commented Jul 20, 2022

@jeroenst: I compiled db4f710 myself and it offered ModBr Tx/Rx. But I don't receive anything yet (trying to read outside temp like in my SML script):

# ModBusBaudrate 19200
# ModBusSerialConfig 3
# ModBusSend {"deviceaddress": 247, "functioncode": 3, "startaddress": 9, "type":"int16", "count":1}

I need to check via plain serial bridge if communication is a problem atm... tomorrow or so...

@jeroenst
Copy link
Contributor

jeroenst commented Jul 20, 2022

@TheChatty I did some improvements in my latest branch, try that instead.

I was confused with the registers which are not 8 but 16 bits.

https://github.com/jeroenst/Tasmota/tree/ModbusTCP

Also have a look at the logging when using weblog 4

I will also have a look at it tomorrow if it still doesn't work.

@jeroenst
Copy link
Contributor

jeroenst commented Jul 21, 2022

@TheChatty Here is a bin file based on my latest commit in the modbustcp branch.

Can you give it a try?

tasmota.bin.gz

@jeroenst
Copy link
Contributor

Here are the PHP tools that I use for simulaton.
modbus tools.zip

@TheChatty
Copy link
Contributor Author

TheChatty commented Jul 21, 2022

I could now use plain serial bridge (again) like this:

baudrate 19200
serialsend5 f7 03 00 09 00 01 40 9e
RESULT = {"SerialSend":"Done"}
RESULT = {"SerialReceived":"F703020115B00E"}

0x0115 --> 227 --> /10 --> 27.7° degrees outside

But still no response via modbus bridge:

ModBusBaudrate 19200
ModBusSend {"deviceaddress": 247, "functioncode": 3, "startaddress": 9, "type":"int16", "count":1}
RESULT = {"ModbusSend":"Done"}

@jeroenst
Copy link
Contributor

Something goes wrong with setting the baudrate.

On 9600 I receive from esp8266: 0xf7 0x03 0x00 0x09 0x00 0x01 0x40 0x9e
On 19200 I receive from esp8266: 0x7e 0x1e 0x00 0x86 0x00 0x06 0x00 0x1e

Investigation in progress..

@jeroenst
Copy link
Contributor

For some reason modbusbaudrate is not working right and it also causes modbusbridge to become deaf to incomming data.

Have to dig further for this to find out why this is happening.

@jeroenst
Copy link
Contributor

@TheChatty
This is a hard thing, in code everything seems right, I even thing serialbridge encounters the same issue.

Can you maybe do a test at 9600 baud (without setting baudrate in tasmota) ?

@TheChatty
Copy link
Contributor Author

At 9600 baud I cannot test with my modbus client as it is fixed to 19200.

What do you want me to test?

@jeroenst
Copy link
Contributor

It seems that data from every slave address greater than 4 is ignored by the modbus driver. Can you test it with address 1 or 2?

@jeroenst
Copy link
Contributor

19200 works fine below slave address 5, debugging now.

@TheChatty
Copy link
Contributor Author

I cannot change any modbus setting at the client side - sorry. Good look with the debugging.

@jeroenst
Copy link
Contributor

ok, almost there I think

@jeroenst
Copy link
Contributor

Bug found, and solved, here is the firmware without bug

tasmota.bin.gz

@TheChatty
Copy link
Contributor Author

3156b06 does not change anything for me - still no response. weblog 4 does not give any hint.

@jeroenst
Copy link
Contributor

jeroenst commented Aug 24, 2022

So this is strange:
TX: 0x00 0x02 0x00 0x00 0x00 0x09 0xf7 0x10 0x00 0x90 0x00 0x06 0xc4 0x96 0x97

14:32:03.862 MBS: MBRTCP to Modbus Transactionid:2, deviceAddress:247, functionCode:16, startAddress:144, sendCount:2, recvCount:1
14:32:03.864 MBS: Serial Send: F7 10 00 90 00 01 02 06 C4 96 97

RX: 0xf7 0x10 0x00 0x90 0x00 0x01 0x02 0x06 0xc4 0x96 0x97

@jeroenst
Copy link
Contributor

jeroenst commented Aug 24, 2022

I may have found something: e9fca82

No doesn't work, but I can reproduce your bug now

Found bug, finding solution.

@jeroenst
Copy link
Contributor

When looking at my serial data it's solved in my latest commit.

@TheChatty
Copy link
Contributor Author

TheChatty commented Aug 24, 2022

c788e80 delivers this:

15:17:56.530 TCP: MBS: MBRTCP Got connection from 192.168.178.41
15:17:56.534 0=0102
15:17:56.536 1=06C4
15:17:56.537 MBS: MBRTCP to Modbus Transactionid:1, deviceAddress:247, functionCode:16, startAddress:144, sendCount:2, recvCount:1
15:17:56.539 MBS: Serial Send: F7 10 00 90 00 02 04 01 02 06 C4 45 47 
15:17:56.640 MBS: Serial Received: F7 90 06 2C 30 
15:17:56.688 MBS: MBRTCP from Modbus deviceAddress 247, writing 9 bytes to client
15:17:56.690 MBS: MBR Driver receive error 6

So F7100090000204010206C44547is sent, but it should be F710009000010206C49697

Things got even worse. Once working read_holding_registers is also not working.

Wireshark log:

TX 00 01 00 00 00 06 f7 03  00 90 00 01
RX 00 01 00 00 00 03 f7 03  07

Weblog:

19:14:39.788 MBS: MBRTCP to Modbus Transactionid:3096, deviceAddress:247, functionCode:3, startAddress:0, sendCount:0, recvCount:1
19:14:39.791 MBS: Serial Send: F7 03 00 00 00 00 51 5C 
19:14:39.883 MBS: Serial Received: F7 03 00 C0 C2 
19:14:39.941 MBS: MBRTCP from Modbus deviceAddress 247, writing 9 bytes to client
19:14:39.943 MBS: MBR Driver receive error 7

@TheChatty
Copy link
Contributor Author

Things got even worse. Once working read_holding_registers is also not working.

Wireshark log:

TX 00 01 00 00 00 06 f7 03  00 90 00 01
RX 00 01 00 00 00 03 f7 03  07

Weblog:

19:14:39.788 MBS: MBRTCP to Modbus Transactionid:3096, deviceAddress:247, functionCode:3, startAddress:0, sendCount:0, recvCount:1
19:14:39.791 MBS: Serial Send: F7 03 00 00 00 00 51 5C 
19:14:39.883 MBS: Serial Received: F7 03 00 C0 C2 
19:14:39.941 MBS: MBRTCP from Modbus deviceAddress 247, writing 9 bytes to client
19:14:39.943 MBS: MBR Driver receive error 7

jeroenst pushed a commit to jeroenst/Tasmota that referenced this issue Aug 24, 2022
@jeroenst
Copy link
Contributor

Try latest commit for FC16 please. Also test if read_holding_registers is working, otherwise I will look at it tomorrow.

@TheChatty
Copy link
Contributor Author

TheChatty commented Aug 24, 2022

read_holding_registers works.

write_registers(0x90, [1732], slave=247) delivers Wireshark log:

TX 00 01 00 00 00 09 f7 10 00 90 00 01 02 06 c4
RX 00 01 00 00 00 06 f7 10 00 90 00 01

And weblog (no more Driver receive errors):

22:26:53.910 TCP: MBS: MBRTCP Got connection from 192.168.178.41
22:26:53.912 0=06C4
22:26:53.914 MBS: MBRTCP to Modbus Transactionid:1, deviceAddress:247, functionCode:16, startAddress:144, sendCount:1, recvCount:1
22:26:53.917 MBS: Serial Send: F7 10 00 90 00 01 02 06 C4 96 97 
22:26:54.097 MBS: Serial Received: F7 10 00 90 00 01 15 72 
22:26:54.111 MBS: MBRTCP from Modbus deviceAddress 247, writing 12 bytes to client

This seems to be the right track. Even Trovis is working (as in: connection does not choke), but at first sight there are some values wrong (bad temperatures). Wireshark shows some malformed packets. In this TCP stream seems to be lot of Tasmota memory data.

Needs to be analyzed.

jeroenst pushed a commit to jeroenst/Tasmota that referenced this issue Aug 25, 2022
Returned bytes need to be even (limitation of TasmotaModbus.cpp)
arendst#9586
@jeroenst
Copy link
Contributor

jeroenst commented Aug 25, 2022

I did some testing and bugfixing for functioncode 1 and 2. For functioncode 1 and 2 also an odd number of bytes can be returned, but this is not supported by TasmotaModbus.cpp.

For function code 15 it's also allowed to send single bytes as data I discovered.

I will adapt TasmotaModbus for this later.

https://ozeki.hu/p_5876-mobdbus-function-code-1-read-coils.html
https://ozeki.hu/p_5877-mobdbus-function-code-2-read-discrete-inputs.html
https://ozeki.hu/p_5882-mobdbus-function-code-15-write-multiple-coils.html

jeroenst pushed a commit to jeroenst/Tasmota that referenced this issue Aug 27, 2022
jeroenst pushed a commit to jeroenst/Tasmota that referenced this issue Aug 27, 2022
jeroenst pushed a commit to jeroenst/Tasmota that referenced this issue Aug 27, 2022
jeroenst pushed a commit to jeroenst/Tasmota that referenced this issue Aug 27, 2022
Returned bytes need to be even (limitation of TasmotaModbus.cpp)
arendst#9586
@jeroenst jeroenst mentioned this issue Aug 27, 2022
6 tasks
@jeroenst
Copy link
Contributor

All code is now in the arendst/Tasmota development branch.

Please create a new bug report if any bug is found, this issue is getting to long.

@jeroenst
Copy link
Contributor

jeroenst commented Aug 27, 2022

@josegardo I don't forget about you, over a few weeks I will include your code/feature request in ModbusBridge.

You are also welcome to create a patch file leaving all other functionality in ModbusBridge in tact.

@darcyg
Copy link

darcyg commented Aug 29, 2022

I did some testing and bugfixing for functioncode 1 and 2. For functioncode 1 and 2 also an odd number of bytes can be returned, but this is not supported by TasmotaModbus.cpp.

For function code 15 it's also allowed to send single bytes as data I discovered.

I will adapt TasmotaModbus for this later.

https://ozeki.hu/p_5876-mobdbus-function-code-1-read-coils.html https://ozeki.hu/p_5877-mobdbus-function-code-2-read-discrete-inputs.html https://ozeki.hu/p_5882-mobdbus-function-code-15-write-multiple-coils.html

Read the code of TasmotaModbus.
When the number of DO/DI of plc is greater than 16. It is not possible to read and write all points at once.
The DI/DO of low cost PLCs I know can go up to 32 points (dedicated PLC cascades can be up to hundreds). At least two WORD lengths need to be read. When the number of the latest code DO/DI is greater than 16, it needs to be read twice.

@henfri
Copy link

henfri commented Sep 2, 2022

Hello,
sorry, it is hard to keep track of this development by reading this issue.
Is this Gateway working now?
Is there any documentation?

Best regards,
Hendrik

@jeroenst
Copy link
Contributor

jeroenst commented Sep 2, 2022

Code is finished but on beta status.

Here you can find the documentation:

https://tasmota.github.io/docs/Modbus-Bridge/

@TheChatty
Copy link
Contributor Author

It is working for me in a low looad environment already, e.g. I can run a python script (ModbusTcpClient) and request single registers from a serial RTU modbus client connected to Tasmota.

What doesn't work for me atm is an application which causes heavy load on the wires (vendor app to configure the heating regulator). The connection seems to choke. I need to further evaluate this.

@henfri
Copy link

henfri commented Sep 10, 2022

Hello,

I am not sure, I understand the feature well.
Is it possible with this to receive Modbus RTU values and send (all) of them via Modbus TCP? (or/and the other way around)

Best regards,
Hendrik

@TheChatty
Copy link
Contributor Author

TheChatty commented Sep 10, 2022

Yes, it's a TCP/RTU gateway. It connects your serial-only modbus device to your Wifi. And you can also send MQTT requests at the same time. Awesome piece of code.

@henfri
Copy link

henfri commented Sep 10, 2022

Great!

But when I go through the documentation, it is not at all clear how to configure that. Please see this as constructive feedback, not as criticism.

The Modbus Bridge driver features 2 kind of bridges.

USE_MODBUS_BRIDGE: The bridge can be used by commands in the console and via MQTT messages.
USE_MODBUS_BRIDGE_TCP: The bridge can be used by commands in the console and via MQTT messages but also as Modbus TCP/IP bridge

It is not clear where to configure that.

Then, it goes directly to Commands.

I would expect something like

In order to use the Modbus Bridge, configure USE_MODBUS_BRIDGE or ..._TCP in config.h and compile Tasmota. This feature is not part of any precompiled Binary and only available for ESP32.
Once, this feature is compiled in, and the GPIOs for ModBus RTU are selected, the Bridge will automatically relay all Data from RTU to TCP and vice versa.

Furthermore, it is possible to send data from MQTT to Modbus (it will send to both RTU and TCP at the same time).
Relaying data from Modbus to MQTT is not supported (?)

A question on this:

ModbusTcpStart | Start the Modbus TCP bridge on the specified tcp port

Is that required to start the Bridge? Autostart possible?

@TheChatty
Copy link
Contributor Author

TheChatty commented Sep 10, 2022

You've got a couple of mistakes in your reply.

The base is to define USE_MODBUS_BRIDGE in user_config_override.h like any other feature that doesn't come precompiled. You have to define GPIOs like they are configured for your serial modbus device. Then you can use MQTT to send modbus requests which will be received via MQTT as well.

Defining USE_MODBUS_BRIDGE_TCP additionally gives you something like Serial to TCP bridge except it provides transparent TCP/RTU protocol translation. No additional GPIOs are required but a start of the TCP server (see similar bridge feature). This start can be automated with rules.

Requests sent with TCP part will only be answered via TCP. Likewise with MQTT.

I haven't tried ESP32 myself yet but I can promise it works well with ESP8266.


You're invited to improve documentation once you got acquainted with this feature. I haven't done so yet because I still analyze a failing heavy load scenario. The similar TCP bridge serves a good start for TCP part of this bridge.

@jeroenst
Copy link
Contributor

@TheChatty thank you for supporting other users.

Maybe for the heavy load scenario I can add a little delay before processing. I can imagine that tasmota gets to little time to process other tasks in heavy load.

jeroenst pushed a commit to jeroenst/Tasmota that referenced this issue Sep 10, 2022
@jeroenst
Copy link
Contributor

@TheChatty can you give my latest commit a try?

@TheChatty
Copy link
Contributor Author

@jeroenst I'm helping others because you did a wonderful job already.

Unfortunately I won't get to test any of this until two weeks. I'll give feedback then.

@jeroenst
Copy link
Contributor

@TheChatty no problem👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request (devs?) Action - awaiting response from developers requested feature (hold over) Result - Feature that will not be added soon (out of scope)
Projects
None yet
10 participants