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.

HomeLynk as Modbus TCP/IP slave
#1
Hello!

Is it possible to setup a Homelynk as a Modbus slave on TCP/IP?

Regards!

P
Reply
#2
Hi
Use this
http://openrb.com/lm-as-modbus-tcp-slave/
BR
------------------------------
Ctrl+F5
Reply
#3
Thanks!

/P
Reply
#4
Hello!

This works fine in genneral but I have an issue with the temperature. When I set the datatype in the script to float16 I get wrong scale on the modbus side. For example if the temperature value is 7.5 on KNX side I get value 7 on modbus side. I should get 750. If I change the datatype in script to int16 it gets completely wrong because temperature on KNX are float16. Are there any way to integrate a multiplier in the script only for float16 objects?
Reply
#5
You should make the conversion outside the script.  Use an virtual object for modbus and make simple event script  like this.

Code:
grp.update('virtual object address', event.getvalue()*100)
------------------------------
Ctrl+F5
Reply
#6
Hello!

Are there any limitations of the amount of adresses in this script above? Or are there any ather better way if there is a lot of adresses? I have a project where I have a modbus master that have to read about 300 adresses.

BR
Per-Åke
Reply
#7
Hi,

Hard to say exactly as it depends on other processes in your controller like amount of KNX object updates etcetera. The indicator of limitations is most of the time the CPU load.

We tested a lot of scenarios / addressable limits and you can see them in this document: https://www.schneider-electric.com/en/download/document/AN017/

On page 13 you can see the results of a test with 1000 objects on a HW2 device (you can increase this on HW3).

So if your controller is not doing anything else then 300 objects should work just fine.

BR,

Erwin
Reply
#8
I have a problem with the script..
I have 2 LM:
LM1 is the one with this script https://openrb.com/lm-as-modbus-tcp-slave
LM2 is the one that need to read LM1

When I try to read with LM1 my LM2, LM2 return tis error:  LM (TCP 192.168.1.91:502) read failed: Illegal data address

The profile in LM2 is this:

Code:
{
"manufacturer":"LM",
"description":"LM",
"mapping":[
{"name":"Reg1", "bus_datatype": "int16", "datatype": "uint16", "type": "register", "address": 0, "writable": true},
{"name":"Reg2", "bus_datatype": "int16", "datatype": "uint16", "type": "register", "address": 1, "writable": true},
{"name":"Reg3", "bus_datatype": "int16", "datatype": "uint16", "type": "register", "address": 2, "writable": true},
{"name":"Reg4", "bus_datatype": "int16", "datatype": "uint16", "type": "register", "address": 3, "writable": true},
{"name":"Reg5", "bus_datatype": "int16", "datatype": "uint16", "type": "register", "address": 4, "writable": true},
{"name":"Reg6", "bus_datatype": "int16", "datatype": "uint16", "type": "register", "address": 5, "writable": true},
{"name":"Reg7", "bus_datatype": "int16", "datatype": "uint16", "type": "register", "address": 6, "writable": true}
]
}
and the script in LM1 is:
Code:
if not mb then
  require('genohm-scada.eibdgm')
  require('luamodbus')

  -- Elenco mappature bobine, a partire da 0
  coils = { '1/1/1' }

  -- Elenco mappature dei registri, a partire da 0
  registers = { "1/2/0", "1/2/3", "1/2/4", "1/2/9", "1/2/14", "1/2/16", "33/0/1" }

  -- Elenco tipo di dati del registro, il conteggio degli elementi deve corrispondere alla tabela dei registri
  regdt = { dt.uint16, dt.uint16, dt.uint16, dt.uint16, dt.uint16, dt.uint16, dt.uint16 }

  -- Richiamo in scrittura del gr. KNX
  function knxgroupwrite(event)
    local value

    -- Prova a trovare la bobona corrispondente
    for id, addr in ipairs(coils) do
      if event.dst == addr then
        value = knxdatatype.decode(event.datahex, dt.bool)
        mb:setcoils(id - 1, value)
      end
    end

    -- Prova a trovare il registro corrispondente
    for id, addr in ipairs(registers) do
      if event.dst == addr then
        value = knxdatatype.decode(event.datahex, regdt[ id ])
        mb:setregisters(id - 1, value)
      end
    end
  end

  -- richiama bobina in scrittura
  function mbwritecoils(coil, value)
    local addr = coils[ coil + 1 ]
    if addr then
      grp.write(addr, value, dt.bool)
    end
  end

  -- registra la chiamata in scrittura
  function mbwriteregisters(register, value)
    local addr = registers[ register + 1 ]
    if addr then
      grp.write(addr, value, regdt[ register + 1])
    end
  end

  -- knx group monitor, gestisce le scritture di gruppo
  knxclient = eibdgm:new({ timeout = 0.1 })
  knxclient:sethandler('groupwrite', knxgroupwrite)

  -- modbus slave, ascolta su tutte le interfaccie e porte default 502
  mb = luamodbus.tcp()
  mb:open('0.0.0.0', 502)

  -- Impostazione Slave (Facoltativa)
  --mb:setslave(1)

  mb:setreceivetimeout(0.1)
  mb:setmapping(#coils, 0, #registers, 0)

  -- Inizializza bobine
  for id, addr in ipairs(coils) do
    value = grp.getvalue(addr)
    mb:setcoils(id - 1, value)
  end

  -- Inizializza registri
  for id, addr in ipairs(registers) do
    value = grp.getvalue(addr)
    mb:setregisters(id - 1, value)
  end

  -- set callbacks for coil and register write
  mb:setwritecoilcb(mbwritecoils)
  mb:setwriteregistercb(mbwriteregisters)
end

-- Gestione modbus e KNX
mb:handleslave()
knxclient:step()
can someone help me?
Reply
#9
Why do you need modbus to communicate between two LMs?
------------------------------
Ctrl+F5
Reply
#10
It is only a test, I need to read from an LM with modbus TCP
Reply
#11
I just tried it like this and it works fine.
Code:
if not mb then
  require('genohm-scada.eibdgm')
  require('luamodbus')

  -- Elenco mappature bobine, a partire da 0
  coils = { '32/1/23' }

  -- Elenco mappature dei registri, a partire da 0
  registers = { "32/1/21", "32/1/22" }

  -- Elenco tipo di dati del registro, il conteggio degli elementi deve corrispondere alla tabela dei registri
  regdt = { dt.uint16, dt.uint16 }

  -- Richiamo in scrittura del gr. KNX
  function knxgroupwrite(event)
    local value

    -- Prova a trovare la bobona corrispondente
    for id, addr in ipairs(coils) do
      if event.dst == addr then
        value = knxdatatype.decode(event.datahex, dt.bool)
        mb:setcoils(id - 1, value)
      end
    end

    -- Prova a trovare il registro corrispondente
    for id, addr in ipairs(registers) do
      if event.dst == addr then
        value = knxdatatype.decode(event.datahex, regdt[ id ])
        mb:setregisters(id - 1, value)
      end
    end
  end

  -- richiama bobina in scrittura
  function mbwritecoils(coil, value)
    local addr = coils[ coil + 1 ]
    if addr then
      grp.write(addr, value, dt.bool)
    end
  end

  -- registra la chiamata in scrittura
  function mbwriteregisters(register, value)
    local addr = registers[ register + 1 ]
    if addr then
      grp.write(addr, value, regdt[ register + 1])
    end
  end

  -- knx group monitor, gestisce le scritture di gruppo
  knxclient = eibdgm:new({ timeout = 0.1 })
  knxclient:sethandler('groupwrite', knxgroupwrite)

  -- modbus slave, ascolta su tutte le interfaccie e porte default 502
  mb = luamodbus.tcp()
  mb:open('0.0.0.0', 502)

  -- Impostazione Slave (Facoltativa)
  --mb:setslave(1)

  mb:setreceivetimeout(0.1)
  mb:setmapping(#coils, 0, #registers, 0)

  -- Inizializza bobine
  for id, addr in ipairs(coils) do
    value = grp.getvalue(addr)
    mb:setcoils(id - 1, value)
  end

  -- Inizializza registri
  for id, addr in ipairs(registers) do
    value = grp.getvalue(addr)
    mb:setregisters(id - 1, value)
  end

  -- set callbacks for coil and register write
  mb:setwritecoilcb(mbwritecoils)
  mb:setwriteregistercb(mbwriteregisters)
end

-- Gestione modbus e KNX
mb:handleslave()
knxclient:step()
profile
Code:
{
  "manufacturer": "Embedded Systems",
  "description": "LM11",
  "mapping": [
    { "name": "Output 1", "bus_datatype": 1, "type": "coil", "address": 0, "writable": 1 },
    { "name": "Input 1", "bus_datatype": 7, "type": "register", "address": 0,  "writable": 1 },
    { "name": "Input 1", "bus_datatype": 7, "type": "register", "address": 1,  "writable": 1 }

  ]
}
------------------------------
Ctrl+F5
Reply
#12
what!? Huh how is it possible? Dodgy

Can I know how you set objects?
Reply
#13
Like this
   
Which FW do you use?
------------------------------
Ctrl+F5
Reply
#14
mmm really strange.. now that I use the same datatype (my fault) I have no error, but I read always 0, no matter what I write into objects..

The FW is 20200116
Reply
#15
Do you use same type objects in both LMs? It works fine in both directions.

Disable and enable the script.
------------------------------
Ctrl+F5
Reply
#16
ok now it works! I have disable and enable again the script and it start working
Reply


Forum Jump: