Posts: 133
Threads: 19
Joined: Apr 2018
Reputation:
0
Hello All,
I have an installation where the SpaceLynk is used as Modbus TCP Master and polling data from 5 Modbus touch panels.
I have set the poll time to 1sec so that the delay when a user presses a button on the touch panel is minimal.
I am testing now with the latest firmware 2.7.0 and I see most of the times like there is a delay of 4-5sec before the object value changes value in the maping window.
Is there a known bug? Its only three coil registers that are polled by the touch panels and in general SL is not busy.
Both devices are on the same Vlan and wired connection. Ping <1ms.
How can I minimize the delay between the button press on the touch panel and object update which writes into the knx?
What is the Persistent Connection checkbox for in the settings tab of the TCP/IP modbus device?
Can this be a network issue?
Posts: 4643
Threads: 24
Joined: Aug 2017
Reputation:
207
Modbus is master slave protocal which means master asks for one value and slave is replaying. Once answer is received then it asks for next value and so on. All this is a single process with single queue for all TCP devices. If a device will not answer in time then you have to add timeout which master will wait for the answer. With TCP the timeout is 3seconds. There are ways to do a block read which can speed things up and then at once you can read multiple registers. Not every slave supports this. See example here
https://forum.logicmachine.net/showthrea...4#pid21834
------------------------------
Ctrl+F5
Posts: 7758
Threads: 42
Joined: Jun 2015
Reputation:
447
If you want quick polling you need to use one resident script per each connection because Modbus mapper can only poll one TCP device at a time.
Use this example as a starting point. The connection is kept open between requests. Multiple registers are read at once to speed things up.
Code: if not mb then
require('luamodbus')
mb = luamodbus.tcp()
mb:open('192.168.0.9')
res, err = mb:connect()
if not res then
mb:close()
mb = nil
log('connect failed', err)
end
end
if mb then
v1, v2, v3 = mb:readregisters(10, 3)
if v1 ~= nil then
grp.checkupdate('1/1/1', v1)
grp.checkupdate('1/1/2', v2)
grp.checkupdate('1/1/3', v3)
else
mb:close()
mb = nil
log('read failed', v2)
end
end
Posts: 133
Threads: 19
Joined: Apr 2018
Reputation:
0
(08.09.2022, 11:28)admin Wrote: If you want quick polling you need to use one resident script per each connection because Modbus mapper can only poll one TCP device at a time.
Use this example as a starting point. The connection is kept open between requests. Multiple registers are read at once to speed things up.
Code: if not mb then
require('luamodbus')
mb = luamodbus.tcp()
mb:open('192.168.0.9')
res, err = mb:connect()
if not res then
mb:close()
mb = nil
log('connect failed', err)
end
end
if mb then
v1, v2, v3 = mb:readregisters(10, 3)
if v1 ~= nil then
grp.checkupdate('1/1/1', v1)
grp.checkupdate('1/1/2', v2)
grp.checkupdate('1/1/3', v3)
else
mb:close()
mb = nil
log('read failed', v2)
end
end
Thank you admin, this sounds very interesting. What is the correct sleep interval for this resident script? If I set to 1sec is this going to poll data every 1sec from the slave?
Where can I define the registers I would like to read? I need register 0,1,2 and is it also possible to write to those register the value of the knx object when its changed? So in the end a bi-directional communication with the touch panel over modbus IP.
Until now I was using the following profile with mapped knx objects and worked in both directions. The only issue was the delay.
Code: {
"manufacturer": "Pro-Face",
"description": "Touch Panel GP4301-T GM Blok 02->10 ",
"mapping": [
{ "name": "Zone 1 On/Off", "bus_datatype": "1001", "type": "coil", "address": 0, "writable": 1, "write_only": 0 },
{ "name": "Zone 2 On/Off", "bus_datatype": "1001", "type": "coil", "address": 1, "writable": 1, "write_only": 0 },
{ "name": "Zone 3 On/Off", "bus_datatype": "1001", "type": "coil", "address": 2, "writable": 1, "write_only": 0 }
]
}
Posts: 7758
Threads: 42
Joined: Jun 2015
Reputation:
447
Use v1, v2, v3 = mb:readcoils(0, 3)
You can keep the profile for writing as combining reading and writing in a single script is rather complicated.
Posts: 133
Threads: 19
Joined: Apr 2018
Reputation:
0
Thank you admin.
As always great support.
Posts: 133
Threads: 19
Joined: Apr 2018
Reputation:
0
09.09.2022, 13:14
(This post was last modified: 09.09.2022, 13:15 by manos@dynamitec.)
Hello admin,
I was testing the resident script (1sec sleep interval) for polling in combination with the modbus profile for writing to the modbus.
The delay is much better now and I like that the objects are being updated quickly into the KNX bus. But I have a new problem when the value of the objects is changed from the KNX bus.
The modbus profile is writing the value to the modbus imediatelly and the touch panel is updated correctly, but while the resident script is running every 1sec the moment it polls the data the slave probably is replying the previous value and this overwrites the value of the knx object. It happens most of sometimes not always.
I am wondering if we can make the resident script with 0sec sleep interval and have a loop with a 1sec delay to do the polling. But in this loop we have to check if the object is written by the KNX bus and pause the loop for some (2) seconds before it can poll the modbus again.
Can something like this be easily implemented?
Thank you in advance for any effort.
Posts: 7758
Threads: 42
Joined: Jun 2015
Reputation:
447
You can use grp.find() to get updatetime field value of an object and compare it with current time (os.time()). For this to work correctly you need to have separate control/status objects. The write to Modbus script can also update status object right after writing.
Posts: 133
Threads: 19
Joined: Apr 2018
Reputation:
0
(12.09.2022, 12:08)admin Wrote: You can use grp.find() to get updatetime field value of an object and compare it with current time (os.time()). For this to work correctly you need to have separate control/status objects. The write to Modbus script can also update status object right after writing.
Could you make an example please? I don't understand in which part of the script I have to implement this and also do you mean that command and status in the modbus touch panel has to be a different register? I dont know if this can be a solution on the modbus side because in most cases the buttons are toggle.
Is there an other workaround?
Regards
Posts: 7758
Threads: 42
Joined: Jun 2015
Reputation:
447
You need to create different objects for control and status. Reading script will update status objects while writing script will use control object values. The reading script will check the time when the control object was updated. If it's less than 2 seconds then the status object will not be updated. The writing script can also update the status object value right away so the status value is synchronized.
Code: if not mb then
require('luamodbus')
mb = luamodbus.tcp()
mb:open('192.168.0.9')
res, err = mb:connect()
if not res then
mb:close()
mb = nil
log('connect failed', err)
end
function update(control, status, value)
local ut = grp.find(control).updatetime
local delta = math.abs(os.time() - ut)
if delta >= 2 then
grp.checkupdate(status, value)
end
end
end
if mb then
v1, v2, v3 = mb:readregisters(10, 3)
if v1 ~= nil then
update('1/1/1', '1/1/4', v1)
update('1/1/2', '1/1/5', v2)
update('1/1/3', '1/1/6', v3)
else
mb:close()
mb = nil
log('read failed', v2)
end
end
|