Code:
if not mb then
require('genohm-scada.eibdgm')
require('luamodbus')
-- list of coil mapping, starting from 0
coils = { '42/7/53' }
-- list of discrete inputs mapping, starting from 0
inputDiscrete = { '40/1/7', '40/1/13', '40/1/57', '40/1/63', '40/1/157', '40/1/163', '40/1/107', '40/1/103' }
-- list of holding register mapping, starting from 0
holdingRegister = { {'40/0/20', dt.uint16}, {'40/0/31', dt.uint16}, {'40/0/36', dt.uint16} }
-- list of input register mapping, starting from 0
inputRegister = {{'40/1/25', dt.float32, 0}, {'40/1/25', 0xFF, 1}, {'40/1/26', dt.float32, 2}, {'40/1/26', 0xFF, 3}, {'40/1/27', dt.float32, 4}, {'40/1/27', 0xFF, 5}, {'40/1/28', dt.float32, 6}, {'40/1/28', 0xFF, 7}, {'40/1/29', dt.float32, 8}, {'40/1/29', 0xFF, 9}, {'40/1/30', dt.float32, 10}, {'40/1/30', 0xFF, 11}, {'40/1/31', dt.float32, 12}, {'40/1/31', 0xFF, 13}, {'40/1/32', dt.float32, 14}, {'40/1/32', 0xFF, 15}, {'40/1/33', dt.float32, 16}, {'40/1/33', 0xFF, 17}, {'40/1/34', dt.float32, 18}, {'40/1/34', 0xFF, 19}, {'40/1/35', dt.float32, 20}, {'40/1/35', 0xFF, 21}, {'40/1/36', dt.float32, 22}, {'40/1/36', 0xFF, 23}, {'40/1/37', dt.float32, 24}, {'40/1/37', 0xFF, 25}, {'40/1/38', dt.float32, 26}, {'40/1/38', 0xFF, 27}, {'40/0/32', dt.uint16, 28}, {'40/0/1', 0xFF, 29},
{'40/1/75', dt.float32, 30}, {'40/1/75', 0xFF, 31}, {'40/1/76', dt.float32, 32}, {'40/1/76', 0xFF, 33}, {'40/1/77', dt.float32, 34}, {'40/1/77', 0xFF, 35}, {'40/1/78', dt.float32, 36}, {'40/1/78', 0xFF, 37}, {'40/1/79', dt.float32, 38}, {'40/1/79', 0xFF, 39}, {'40/1/80', dt.float32, 40}, {'40/1/80', 0xFF, 41}, {'40/1/81', dt.float32, 42}, {'40/1/81', 0xFF, 43}, {'40/1/82', dt.float32, 44}, {'40/1/82', 0xFF, 45}, {'40/1/83', dt.float32, 46}, {'40/1/83', 0xFF, 47}, {'40/1/84', dt.float32, 48}, {'40/1/84', 0xFF, 49}, {'40/1/85', dt.float32, 50}, {'40/1/85', 0xFF, 51}, {'40/1/86', dt.float32, 52}, {'40/1/86', 0xFF, 53}, {'40/1/87', dt.float32, 54}, {'40/1/87', 0xFF, 55}, {'40/1/88', dt.float32, 56}, {'40/1/88', 0xFF, 57}, {'40/0/37', dt.uint16, 58}, {'40/0/1', 0xFF, 59},
{'40/1/175', dt.float32, 60}, {'40/1/175', 0xFF, 61}, {'40/1/176', dt.float32, 62}, {'40/1/176', 0xFF, 63}, {'40/1/177', dt.float32, 64}, {'40/1/177', 0xFF, 65}, {'40/1/178', dt.float32, 66}, {'40/1/178', 0xFF, 67}, {'40/1/179', dt.float32, 68}, {'40/1/179', 0xFF, 69}, {'40/1/180', dt.float32, 70}, {'40/1/180', 0xFF, 71}, {'40/1/181', dt.float32, 72}, {'40/1/181', 0xFF, 73}, {'40/1/182', dt.float32, 74}, {'40/1/182', 0xFF, 75}, {'40/1/183', dt.float32, 76}, {'40/1/183', 0xFF, 77}, {'40/1/184', dt.float32, 78}, {'40/1/184', 0xFF, 79}, {'40/1/185', dt.float32, 80}, {'40/1/185', 0xFF, 81}, {'40/1/186', dt.float32, 82}, {'40/1/186', 0xFF, 83}, {'40/1/187', dt.float32, 84}, {'40/1/187', 0xFF, 85}, {'40/1/188', dt.float32, 86}, {'40/1/188', 0xFF, 87}, {'40/0/1', 0xFF, 88}, {'40/0/1', 0xFF, 89},
{'40/1/25', dt.float32, 90}, {'40/1/25', 0xFF, 91}, {'40/1/26', dt.float32, 92}, {'40/1/26', 0xFF, 93}, {'40/1/27', dt.float32, 94}, {'40/1/27', 0xFF, 95}, {'40/0/40', dt.float32, 96}, {'40/0/40', 0xFF, 97}, {'40/0/41', dt.float32, 98}, {'40/0/41', 0xFF, 99}, {'40/0/42', dt.float32, 100}, {'40/0/42', 0xFF, 101}, {'40/0/43', dt.float32, 102}, {'40/0/43', 0xFF, 103}, {'40/0/44', dt.float32, 104}, {'40/0/44', 0xFF, 105}, {'40/0/45', dt.float32, 106}, {'40/0/45', 0xFF, 107}, {'40/0/46', dt.float32, 108}, {'40/0/46', 0xFF, 109}, {'40/0/47', dt.float32, 110}, {'40/0/47', 0xFF, 111}, {'40/0/48', dt.float32, 112}, {'40/0/48', 0xFF, 113},
{'40/1/125', dt.float32, 114}, {'40/1/125', 0xFF, 115}, {'40/1/126', dt.float32, 116}, {'40/1/126', 0xFF, 117}, {'40/1/127', dt.float32, 118}, {'40/1/127', 0xFF, 119}, {'40/1/128', dt.float32, 120}, {'40/1/128', 0xFF, 121}, {'40/1/129', dt.float32, 122}, {'40/1/129', 0xFF, 123}, {'40/1/130', dt.float32, 124}, {'40/1/130', 0xFF, 125}, {'40/1/131', dt.float32, 126}, {'40/1/131', 0xFF, 127}, {'40/1/132', dt.float32, 128}, {'40/1/132', 0xFF, 129}, {'40/1/133', dt.float32, 130}, {'40/1/133', 0xFF, 131}, {'40/1/134', dt.float32, 132}, {'40/1/134', 0xFF, 133}, {'40/1/135', dt.float32, 134}, {'40/1/135', 0xFF, 135}, {'40/1/136', dt.float32, 136}, {'40/1/136', 0xFF, 137}, {'40/1/137', dt.float32, 138}, {'40/1/137', 0xFF, 139}, {'40/1/138', dt.float32, 140}, {'40/1/138', 0xFF, 141}, {'40/1/140', dt.float32, 142}, {'40/1/140', 0xFF, 143}, {'40/1/141', dt.float32, 144}, {'40/1/141', 0xFF, 145}, {'40/1/142', dt.float32, 146}, {'40/1/142', 0xFF, 147}, {'40/1/143', dt.uint16, 148}, {'40/1/144', dt.uint16, 149},
{'40/4/72', dt.float32, 150}, {'40/4/72', 0xFF, 151}, {'40/4/73', dt.float32, 152}, {'40/4/73', 0xFF, 153}, {'40/4/74', dt.float32, 154}, {'40/4/74', 0xFF, 155}, {'40/4/75', dt.float32, 156}, {'40/4/75', 0xFF, 157}, {'40/4/76', dt.float32, 158}, {'40/4/76', 0xFF, 159}, {'40/4/77', dt.float32, 160}, {'40/4/77', 0xFF, 161}, {'40/4/78', dt.float32, 162}, {'40/4/78', 0xFF, 163}, {'40/4/80', dt.float32, 164}, {'40/4/80', 0xFF, 165}, {'40/4/81', dt.float32, 166}, {'40/4/81', 0xFF, 167}, {'40/4/82', dt.uint32, 168}, {'40/4/83', dt.uint32, 170}, {'40/4/70', dt.uint16, 172}, {'40/4/71', dt.uint16, 173}, {'40/4/21', dt.uint16, 174}, {'40/4/60', dt.uint16, 175}, {'40/0/1', 0xFF, 176}, {'40/0/1', 0xFF, 177}, {'40/0/1', 0xFF, 178}, {'40/0/1', 0xFF, 179},
{'40/5/72', dt.float32, 180}, {'40/5/72', 0xFF, 181}, {'40/5/73', dt.float32, 182}, {'40/5/73', 0xFF, 183}, {'40/5/74', dt.float32, 184}, {'40/5/74', 0xFF, 185}, {'40/5/75', dt.float32, 186}, {'40/5/75', 0xFF, 187}, {'40/5/76', dt.float32, 188}, {'40/5/76', 0xFF, 189}, {'40/5/77', dt.float32, 190}, {'40/5/77', 0xFF, 191}, {'40/5/78', dt.float32, 192}, {'40/5/78', 0xFF, 193}, {'40/5/80', dt.float32, 194}, {'40/5/80', 0xFF, 195}, {'40/5/81', dt.float32, 196}, {'40/5/81', 0xFF, 197}, {'40/5/82', dt.uint32, 198}, {'40/5/83', dt.uint32, 200}, {'40/5/70', dt.uint16, 202}, {'40/5/71', dt.uint16, 203}, {'40/5/21', dt.uint16, 204}, {'40/5/60', dt.uint16, 205}, {'40/0/1', 0xFF, 206}, {'40/0/1', 0xFF, 207}, {'40/0/1', 0xFF, 208}, {'40/0/1', 0xFF, 209},
{'40/6/72', dt.float32, 210}, {'40/6/72', 0xFF, 211}, {'40/6/73', dt.float32, 212}, {'40/6/73', 0xFF, 213}, {'40/6/74', dt.float32, 214}, {'40/6/74', 0xFF, 215}, {'40/6/75', dt.float32, 216}, {'40/6/75', 0xFF, 217}, {'40/6/76', dt.float32, 218}, {'40/6/76', 0xFF, 219}, {'40/6/77', dt.float32, 220}, {'40/6/77', 0xFF, 221}, {'40/6/78', dt.float32, 222}, {'40/6/78', 0xFF, 223}, {'40/6/80', dt.float32, 224}, {'40/6/80', 0xFF, 225}, {'40/6/81', dt.float32, 226}, {'40/6/81', 0xFF, 227}, {'40/6/82', dt.uint32, 228}, {'40/6/83', dt.uint32, 230}, {'40/6/70', dt.uint16, 232}, {'40/6/71', dt.uint16, 233}, {'40/6/21', dt.uint16, 234}, {'40/6/60', dt.uint16, 235}, {'40/0/1', 0xFF, 236}, {'40/0/1', 0xFF, 237}, {'40/0/1', 0xFF, 238}, {'40/0/1', 0xFF, 239},
{'40/7/72', dt.float32, 240}, {'40/7/72', 0xFF, 241}, {'40/7/73', dt.float32, 242}, {'40/7/73', 0xFF, 243}, {'40/7/74', dt.float32, 244}, {'40/7/74', 0xFF, 245}, {'40/7/75', dt.float32, 246}, {'40/7/75', 0xFF, 247}, {'40/7/76', dt.float32, 248}, {'40/7/76', 0xFF, 249}, {'40/7/77', dt.float32, 250}, {'40/7/77', 0xFF, 251}, {'40/7/78', dt.float32, 252}, {'40/7/78', 0xFF, 253}, {'40/7/80', dt.float32, 254}, {'40/7/80', 0xFF, 255}, {'40/7/81', dt.float32, 256}, {'40/7/81', 0xFF, 257}, {'40/7/82', dt.uint32, 258}, {'40/7/83', dt.uint32, 260}, {'40/7/70', dt.uint16, 262}, {'40/7/71', dt.uint16, 263}, {'40/7/21', dt.uint16, 264}, {'40/7/60', dt.uint16, 265}, {'40/0/1', 0xFF, 266}, {'40/0/1', 0xFF, 267}, {'40/0/1', 0xFF, 268}, {'40/0/1', 0xFF, 269},
{'41/0/72', dt.float32, 270}, {'41/0/72', 0xFF, 271}, {'41/0/73', dt.float32, 272}, {'41/0/73', 0xFF, 273}, {'41/0/74', dt.float32, 274}, {'41/0/74', 0xFF, 275}, {'41/0/75', dt.float32, 276}, {'41/0/75', 0xFF, 277}, {'41/0/76', dt.float32, 278}, {'41/0/76', 0xFF, 279}, {'41/0/77', dt.float32, 280}, {'41/0/77', 0xFF, 281}, {'41/0/78', dt.float32, 282}, {'41/0/78', 0xFF, 283}, {'41/0/80', dt.float32, 284}, {'41/0/80', 0xFF, 285}, {'41/0/81', dt.float32, 286}, {'41/0/81', 0xFF, 287}, {'41/0/82', dt.uint32, 288}, {'41/0/83', dt.uint32, 290}, {'41/0/70', dt.uint16, 292}, {'41/0/71', dt.uint16, 293}, {'41/0/21', dt.uint16, 294}, {'41/0/60', dt.uint16, 295}, {'40/0/1', 0xFF, 296}, {'40/0/1', 0xFF, 297}, {'40/0/1', 0xFF, 298}, {'40/0/1', 0xFF, 299},
{'41/1/72', dt.float32, 300}, {'41/1/72', 0xFF, 301}, {'41/1/73', dt.float32, 302}, {'41/1/73', 0xFF, 303}, {'41/1/74', dt.float32, 304}, {'41/1/74', 0xFF, 305}, {'41/1/75', dt.float32, 306}, {'41/1/75', 0xFF, 307}, {'41/1/76', dt.float32, 308}, {'41/1/76', 0xFF, 309}, {'41/1/77', dt.float32, 310}, {'41/1/77', 0xFF, 311}, {'41/1/78', dt.float32, 312}, {'41/1/78', 0xFF, 313}, {'41/1/80', dt.float32, 314}, {'41/1/80', 0xFF, 315}, {'41/1/81', dt.float32, 316}, {'41/1/81', 0xFF, 317}, {'41/1/82', dt.uint32, 318}, {'41/1/83', dt.uint32, 320}, {'41/1/70', dt.uint16, 322}, {'41/1/71', dt.uint16, 323}, {'41/1/21', dt.uint16, 324}, {'41/1/60', dt.uint16, 325}, {'40/0/1', 0xFF, 326}, {'40/0/1', 0xFF, 327}, {'40/0/1', 0xFF, 328}, {'40/0/1', 0xFF, 329},
{'41/2/72', dt.float32, 330}, {'41/2/72', 0xFF, 331}, {'41/2/73', dt.float32, 332}, {'41/2/73', 0xFF, 333}, {'41/2/74', dt.float32, 334}, {'41/2/74', 0xFF, 335}, {'41/2/75', dt.float32, 336}, {'41/2/75', 0xFF, 337}, {'41/2/76', dt.float32, 338}, {'41/2/76', 0xFF, 339}, {'41/2/77', dt.float32, 340}, {'41/2/77', 0xFF, 341}, {'41/2/78', dt.float32, 342}, {'41/2/78', 0xFF, 343}, {'41/2/80', dt.float32, 344}, {'41/2/80', 0xFF, 345}, {'41/2/81', dt.float32, 346}, {'41/2/81', 0xFF, 347}, {'41/2/82', dt.uint32, 348}, {'41/2/83', dt.uint32, 350}, {'41/2/70', dt.uint16, 352}, {'41/2/71', dt.uint16, 353}, {'41/2/21', dt.uint16, 354}, {'41/2/60', dt.uint16, 355}, {'40/0/1', 0xFF, 356}, {'40/0/1', 0xFF, 357}, {'40/0/1', 0xFF, 358}, {'40/0/1', 0xFF, 359},
{'41/3/72', dt.float32, 360}, {'41/3/72', 0xFF, 361}, {'41/3/73', dt.float32, 362}, {'41/3/73', 0xFF, 363}, {'41/3/74', dt.float32, 364}, {'41/3/74', 0xFF, 365}, {'41/3/75', dt.float32, 366}, {'41/3/75', 0xFF, 367}, {'41/3/76', dt.float32, 368}, {'41/3/76', 0xFF, 369}, {'41/3/77', dt.float32, 370}, {'41/3/77', 0xFF, 371}, {'41/3/78', dt.float32, 372}, {'41/3/78', 0xFF, 373}, {'41/3/80', dt.float32, 374}, {'41/3/80', 0xFF, 375}, {'41/3/81', dt.float32, 376}, {'41/3/81', 0xFF, 377}, {'41/3/82', dt.uint32, 378}, {'41/3/83', dt.uint32, 380}, {'41/3/70', dt.uint16, 382}, {'41/3/71', dt.uint16, 383}, {'41/3/21', dt.uint16, 384}, {'41/3/60', dt.uint16, 385}, {'40/0/1', 0xFF, 386}, {'40/0/1', 0xFF, 387}, {'40/0/1', 0xFF, 388}, {'40/0/1', 0xFF, 389},
{'41/4/72', dt.float32, 390}, {'41/4/72', 0xFF, 391}, {'41/4/73', dt.float32, 392}, {'41/4/73', 0xFF, 393}, {'41/4/74', dt.float32, 394}, {'41/4/74', 0xFF, 395}, {'41/4/75', dt.float32, 396}, {'41/4/75', 0xFF, 397}, {'41/4/76', dt.float32, 398}, {'41/4/76', 0xFF, 399}, {'41/4/77', dt.float32, 400}, {'41/4/77', 0xFF, 401}, {'41/4/78', dt.float32, 402}, {'41/4/78', 0xFF, 403}, {'41/4/80', dt.float32, 404}, {'41/4/80', 0xFF, 405}, {'41/4/81', dt.float32, 406}, {'41/4/81', 0xFF, 407}, {'41/4/82', dt.uint32, 408}, {'41/4/83', dt.uint32, 410}, {'41/4/70', dt.uint16, 412}, {'41/4/71', dt.uint16, 413}, {'41/4/21', dt.uint16, 414}, {'41/4/60', dt.uint16, 415}, {'40/0/1', 0xFF, 416}, {'40/0/1', 0xFF, 417}, {'40/0/1', 0xFF, 418}, {'40/0/1', 0xFF, 419},
{'41/5/72', dt.float32, 420}, {'41/5/72', 0xFF, 421}, {'41/5/73', dt.float32, 422}, {'41/5/73', 0xFF, 423}, {'41/5/74', dt.float32, 424}, {'41/5/74', 0xFF, 425}, {'41/5/75', dt.float32, 426}, {'41/5/75', 0xFF, 427}, {'41/5/76', dt.float32, 428}, {'41/5/76', 0xFF, 429}, {'41/5/77', dt.float32, 430}, {'41/5/77', 0xFF, 431}, {'41/5/78', dt.float32, 432}, {'41/5/78', 0xFF, 433}, {'41/5/80', dt.float32, 434}, {'41/5/80', 0xFF, 435}, {'41/5/81', dt.float32, 436}, {'41/5/81', 0xFF, 437}, {'41/5/82', dt.uint32, 438}, {'41/5/83', dt.uint32, 440}, {'41/5/70', dt.uint16, 442}, {'41/5/71', dt.uint16, 443}, {'41/5/21', dt.uint16, 444}, {'41/5/60', dt.uint16, 445} }
-- knx group write callback
function knxgroupwrite(event)
local value
-- try to find matching coil
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
-- try to find matching holding register
for id, addr in ipairs(holdingRegister) do
if event.dst == addr[1] then
value = knxdatatype.decode(event.datahex, addr[2])
mb:setregisters(id - 1, value)
end
end
-- try to find matching discrete input
for id, addr in ipairs(inputDiscrete) do
if event.dst == addr then
value = knxdatatype.decode(event.datahex, dt.bool)
mb:setdiscreteinputs(id - 1, value)
end
end
-- try to find matching input register
for id, addr in ipairs(inputRegister) do
if event.dst == addr[1] then
if (addr[2] == dt.float32) then
value = knxdatatype.decode(string.sub(event.datahex, 1, 4), dt.uint32)
mb:setinputregisters(1 + addr[3], value)
value = knxdatatype.decode(string.sub(event.datahex, -4), dt.uint32)
mb:setinputregisters((addr[3]), value)
elseif (addr[2] == 0xFF) then
else
value = knxdatatype.decode(event.datahex, addr[2])
mb:setinputregisters(addr[3], value)
end
end
end
end
-- coil write callback
function mbwritecoils(coil, value)
local addr = coils[ coil + 1 ]
if addr then
grp.write(addr, value, dt.bool)
end
end
-- register write callback
function mbwriteregisters(register, value)
local addr = holdingRegister[register + 1][1]
if addr then
grp.write(addr, value, holdingRegister[register + 1][2])
end
end
-- knx group monitor, handles group writes
knxclient = eibdgm:new({ timeout = 0.1 })
knxclient: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(#coils, #inputDiscrete, #holdingRegister, #inputRegister)
-- init coils
for id, addr in ipairs(coils) do
value = grp.getvalue(addr)
mb:setcoils(id - 1, value)
end
-- init registers
for id, addr in ipairs(holdingRegister) do
value = grp.getvalue(addr[1])
mb:setregisters(id - 1, value)
end
for id, addr in ipairs(inputRegister) do
if (addr[2] == dt.float32) then
--value = grp.getvalue(addr[1])
--value = 0
--grp.update(addr[1], grp.getvalue(addr[1]))
--mb:setinputregisters(addr[3], value)
--mb:setinputregisters((1 + addr[3]), value)
elseif (addr[2] == 0xFF) then
else
value = grp.getvalue(addr[1])
mb:setinputregisters(addr[3], value)
end
end
--[[
for id, addr in ipairs(inputRegister) do
value = grp.getvalue(addr[1])
mb:setinputregisters(id - 1, value)
end
--]]
-- set callbacks for coil and register write
mb:setwritecoilcb(mbwritecoils)
mb:setwriteregistercb(mbwriteregisters)
end
-- handle modbus and knx
mb:handleslave()
knxclient:step()