Actual Modbus addressing starts from 0. Documentation for some devices have addressing starting from 1 which creates confusion.
Here's modified slave script where you can specify addresses directly and there can be gaps in register map, for example: 0..15 for meter 1; 100..115 for meter 2 etc.
This script supports 16-bit values only. If only one way communication is needed (Modbus values are read-only) then it can be modified to support 32-bit and 64-bit values internally without additional scripts for splitting values into 16-bit parts.
Code:
if not mb then
require('luamodbus')
-- list of coil mapping, register mapping and register data types
coils, registers, regdt = {}, {}, {}
-- coil definition
coils[ 0 ] = '1/1/1'
coils[ 1 ] = '1/1/2'
-- register definition
registers[ 0 ] = '2/2/2'
regdt[ 0 ] = dt.int8
registers[ 1 ] = '2/2/3'
regdt[ 1 ] = dt.uint16
-- knx group write callback
function knxgroupwrite(event)
local value
-- try to find matching coil
for id, addr in pairs(coils) do
if event.dst == addr then
value = busdatatype.decode(event.datahex, dt.bool)
mb:setcoils(id, value)
end
end
-- try to find matching register
for id, addr in pairs(registers) do
if event.dst == addr then
value = busdatatype.decode(event.datahex, regdt[ id ])
mb:setregisters(id, value)
end
end
end
-- coil write callback
function mbwritecoils(coil, value)
local addr = coils[ coil ]
if addr then
grp.write(addr, value, dt.bool)
end
end
-- register write callback
function mbwriteregisters(register, value)
local addr = registers[ register ]
if addr then
grp.write(addr, value, regdt[ register])
end
end
-- knx group monitor, handles group writes
busclient = require('localbus').new(0.1)
busclient:sethandler('groupwrite', knxgroupwrite)
-- modbus slave, listen on all interfaces and default port 502
mb = luamodbus.tcp()
mb:open('0.0.0.0', 502)
-- setting slave id is optional
-- mb:setslave(1)
mb:setreceivetimeout(0.1)
mb:setmapping(table.maxn(coils) + 1, 0, table.maxn(registers) + 1, 0)
-- init coils
for id, addr in pairs(coils) do
value = grp.getvalue(addr)
mb:setcoils(id, value)
end
-- init registers
for id, addr in pairs(registers) do
value = grp.getvalue(addr)
mb:setregisters(id, value)
end
-- set callbacks for coil and register write
mb:setwritecoilcb(mbwritecoils)
mb:setwriteregistercb(mbwriteregisters)
end
-- handle modbus and knx
mb:handleslave()
busclient:step()