This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Modbus TCP Polling Delay
#1
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?
Reply
#2
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
Reply
#3
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
Reply
#4
(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 }
  ]
}
Reply
#5
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.
Reply
#6
Thank you admin. Smile 

As always great support.
Reply
#7
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.
Reply
#8
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.
Reply
#9
(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
Reply
#10
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
Reply


Forum Jump: