Closed TheChatty closed 3 years ago
Tasmota always prefers MQTT protocol wherever it's possible. We strongly suggest to use the Mqtt gateway instead.
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).
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
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).
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.
Closing this request as there is no active development on this. Please, ask to reopen if you want to work on this. Thanks.
@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.
I flashed the .gz you provided but are unable to select "ModBr .." in Configuration? It's not listed.
I will look at it tomorrow. Otherwise compile it from my branch.
@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.
@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...
@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.
@TheChatty Here is a bin file based on my latest commit in the modbustcp branch.
Can you give it a try?
Here are the PHP tools that I use for simulaton. modbus tools.zip
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"}
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..
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.
@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) ?
At 9600 baud I cannot test with my modbus client as it is fixed to 19200.
What do you want me to test?
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?
19200 works fine below slave address 5, debugging now.
I cannot change any modbus setting at the client side - sorry. Good look with the debugging.
ok, almost there I think
Bug found, and solved, here is the firmware without bug
3156b06 does not change anything for me - still no response. weblog 4
does not give any hint.
Do you execute ModBusBaudrate 19200 ?
Here it seems to work:
19:51:30.028 CMD: ModBusSend {"deviceaddress": 247, "functioncode": 3, "startaddress": 9, "type":"int16", "count":1}
19:51:30.035 CMD: Grp 0, Cmd 'MODBUSSEND', Idx 1, Len 87, Pld -99, Data '{"deviceaddress": 247, "functioncode": 3, "startaddress": 9, "type":"int16", "count":1}'
19:51:30.043 RSL: RESULT = {"ModbusSend":"Done"}
19:51:30.353 MBS: DATA_RECEIVED1 Address=247
19:51:30.357 RSL: RESULT = {"ModbusReceived":{"DeviceAddress":247,"FunctionCode":3,"StartAddress":9,"Length":7,"Count":1,"Values":[277]}}
did you use the provided .bin.gz file?
No... I compiled 3156b06 myself. I get no response regardless of whether I issue ModBusBaudrate 19200
upfront or not.
Please try the bin.gz file maybe some defines are different.
When building you have to define USE_MODBUS_BRIDGE and USE_MODBUS_TCP_BRIDGE
Now flashed you bin.gz with same results. Did ModBusSend ...
and ModBusBaudrate ...
and another ModBusSend ...
. No response.
I will test ModBus_TCP_Bridge once the other is working ;-)
Over here it is working fine, I even used the exact data you provided.
Maybe something is incorrectly configured like parity?
20:05:22.714 CMD: ModBusSend {"deviceaddress": 247, "functioncode": 3, "startaddress": 9, "type":"int16", "count":1}
20:05:22.719 CMD: Grp 0, Cmd 'MODBUSSEND', Idx 1, Len 87, Pld -99, Data '{"deviceaddress": 247, "functioncode": 3, "startaddress": 9, "type":"int16", "count":1}'
20:05:22.725 RSL: RESULT = {"ModbusSend":"Done"}
20:05:23.038 RSL: RESULT = {"ModbusReceived":{"DeviceAddress":247,"FunctionCode":3,"StartAddress":9,"Length":7,"Count":1,"Values":[277]}}
20:05:32.011 WIF: Checking connection...
That was it. After redoing ModBusSerialConfig 3
it worked. ... I am testing now.
ModBusSerialConfig
is not persisted... it's always 8E1 after reboot.
ModBusBaudrate
looks like it's persisted but probably not run during boot up. I still have to set it manually.
ModBusTCPStart 90
# running tcp modbus 'server' asking for same request as above
TCP: MBS: MBRTCP Got connection from 192.168.178.53
RSL: RESULT = {"SerialReceived":"F7030200F5B016"}
But the 'server' does not get the correct result. Modbus Error: [Invalid Message] No response received, expected at least 8 bytes (0 received)
(timeout is a whopping 10s) Maybe you need to flush the response?
Ok, perfect. In the meantime I bricked my esp which is communicating with an SDM120, that's a thing to fix tomorrow.
Sorry to hear about your loss.
I fixed it this morning so everything is ok, I'm glad it starts working!
@TheChatty Ok, I found the problem there seems to be a TasmotaModbus->begin() and a TasmotaModbus->Begin() function. The first one calls the function from TasmotaSerial->begin which returns different value. Now using Begin the serialclaim function is called and al data received by serial is parsed to the tasmotamodbus driver.
Please give it a try.
Settings are still not persisted as described above.
MQTT with serial@19200b still works.
TCP 'server' (strange definition ModBus uses here) receives something but not understood.
RSL: RESULT = {"ModbusTCPStart":"Done"}
TCP: MBS: MBRTCP Got connection from 192.168.178.53
MBS: Serial data ready 5
MBS: Serial data received buffer = 4
MBS: MBRTCP from Modbus deviceAddress 247, writing 11 bytes to client
DEBUG:pymodbus.client.sync:Connection to Modbus server established. Socket ('192.168.178.53', 64995)
DEBUG:pymodbus.transaction:Current transaction state - IDLE
DEBUG:pymodbus.transaction:Running transaction 1
DEBUG:pymodbus.transaction:SEND: 0x0 0x1 0x0 0x0 0x0 0x6 0xf7 0x3 0x0 0x9 0x0 0x1
DEBUG:pymodbus.client.sync:New Transaction state 'SENDING'
DEBUG:pymodbus.transaction:Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
DEBUG:pymodbus.transaction:Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
DEBUG:pymodbus.transaction:RECV: 0x0 0x1 0x0 0x0 0x0 0x4 0xf7 0x3 0x0 0xde
DEBUG:pymodbus.framer.socket_framer:Processing: 0x0 0x1 0x0 0x0 0x0 0x4 0xf7 0x3 0x0 0xde
DEBUG:pymodbus.factory:Factory Response[ReadHoldingRegistersResponse: 3]
DEBUG:pymodbus.transaction:Adding transaction 1
DEBUG:pymodbus.transaction:Getting transaction 1
DEBUG:pymodbus.transaction:Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
Traceback (most recent call last):
File "minimal_PyModbus_tcp_tasmota.py", line 9, in <module>
print('Temp. outside %s°C' % (client.read_holding_registers( 9,1,unit=247).registers[0]/10))
IndexError: list index out of range
Can you add python logging from a successful request? As far as I can see the data is correct according to the tcp modbus documentation. Maybe I missed something...
I think I had to add a byte count register in the tcp reply message according to the documentation found here: https://www.manualslib.com/manual/1708763/Accuenergy-Axm-Web2.html?page=27#manual
Please try latest commit in my ModbusTCP branch.
These settings are not persistent indeed, you can create a small rule System#Boot
Rule1 On System#Boot DO ModbusBaudrate 19200 ENDON ON System#Boot DO ModbusSerialConfig 3 ENDON ON System#Boot DO ModbusTCPStart 8000 ENDON
Rule1 on
@arendst Should these settings be persistent or is using a boot rule to set modbus parameters the way to go?
I wrote a small ModBus server using pymodbus. That's the log output:
# served by your tcp bridge
DEBUG:pymodbus.transaction:RECV: 0x0 0x1 0x0 0x0 0x0 0x4 0xf7 0x3 0x0 0xde
# served by pymodbus
DEBUG:pymodbus.transaction:RECV: 0x0 0x1 0x0 0x0 0x0 0x5 0xf7 0x3 0x2 0x0 0xde
That looks like a byte counter... will now try your latest code.
MQTT and TCP via pymodbus-client works smoothly in (quasi) parallel. And I can read several registers with a single command or with several consecutive commands. Well done!
Plain serial bridge settings are persisted across boots. Here and with modbus bridge you can see the "Saved conf in flash" message after setting e.g. baudrate.
What I still have to analyze: the Windows and iOS tool suite for my heating regulator still cannot communicate via modbus tcp bridge.
I wrote a small ModBus server using pymodbus. That's the log output:
# served by your tcp bridge DEBUG:pymodbus.transaction:RECV: 0x0 0x1 0x0 0x0 0x0 0x4 0xf7 0x3 0x0 0xde # served by pymodbus DEBUG:pymodbus.transaction:RECV: 0x0 0x1 0x0 0x0 0x0 0x5 0xf7 0x3 0x2 0x0 0xde
That looks like a byte counter... will now try your latest code.
I'm missing the register count bytes in this example, is that on purpose?
You got the chronological order wrong. Your cited message was created BEFORE you updated your code. The last line of the message was: will now try your latest code. To be specific: 56c07ec inserts the once missing byte count and works absolutely fine with MQTT and TCP as long as using pymodbus. But TrovisView is probably not sticking to modbus standard and communicates slightly different which the heating regulator (also) understands. As I said: I will try to analyze this later.
Sorry, I now see it are replies, not requests, you can ignore my message
Btw I tested the modbussend command with an sdm120 modbus electricity meter and it worked like it should.
If TrovisView is not according to the standard and the change is minimal I can take a look if I can add an extra define for it.
But you have to provide a description for the bytes to send and the bytes to receive for the TCP socket.
Please open a new feature request for Modbus RTU to Trovis TCP gateway as this Modbus RTU to TCP gateway is created according the Modbus TCP specifications.
I'm still in the works with figuring out what TrovisView does.
But to the modbus TCP bridge standard:
Baudrate <x>
and TCPBaudrate <y>
for yourself)ModBusBaudrate
always returns RESULT = {"ModbusBaudrate":8912700}
, e.g. destroys current configI will check the persistence, I inherited this code from other modules, so possible persistence is not supported. You can use the Rules I stated earlier instead. (https://github.com/arendst/Tasmota/issues/9586#issuecomment-1192466036)
I will also check the ModbusBaudrate command with no parameters.
For your TrovisView TCP you should open a new change request because that is a different protocol than Modbus TCP specifies.
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)