Logic Machine Forum
Modbus mappings automation - Printable Version

+- Logic Machine Forum (https://forum.logicmachine.net)
+-- Forum: LogicMachine eco-system (https://forum.logicmachine.net/forumdisplay.php?fid=1)
+--- Forum: Scripting (https://forum.logicmachine.net/forumdisplay.php?fid=8)
+--- Thread: Modbus mappings automation (/showthread.php?tid=6054)



Modbus mappings automation - pawel200388 - 21.07.2025

Hi,

I strive to add a funtion to automatically map modbus registers to selected group addresses.

Code:
function mapModbusRegisterToKnx(knxGA, regNum, regType, valueBitmask)

local sql = string.format(
  "SELECT id FROM modbus_mapping WHERE type='%s' AND address=%d",
  regType, reg
)
local rows = db:getall(sql)
if not rows or #rows == 0 then
  return false
end
local updateFields = {
  bus_address  = gaDec,
  bus_write    = 1,
  value_delta  = 0.1,
  value_custom = "rfid"
}
if valueBitmask ~= nil then
  updateFields.value_bitmask = valueBitmask
end

for _, rec in ipairs(rows) do
  db:update("modbus_mapping", updateFields, { id = rec.id })
  log(("✅ Zaktualizowano Modbus %s[%d] → KNX %s (id=%d)%s")
    :format(
      regType, reg, knxGA, rec.id,
      valueBitmask and (", bitmask=" .. tostring(valueBitmask)) or ""
    )
  )
end
end

The problem it works for registers without bitmask:
Code:
mapModbusRegisterToKnx("60/0/93",1299,"register")


but I can't figure out how to make it to work with bitmasks:
Code:
mapModbusRegisterToKnx("60/0/94",1300,"register", "0x01")
mapModbusRegisterToKnx("60/0/95",1300,"register", "0x02")



RE: Modbus mappings automation - admin - 21.07.2025

1. Don't modify value_bitmask, change the SELECT statement to look for a specific value_bitmask if specified.

2. Remove quotes around hexadecimal numbers (0x01 instead of "0x01").

3. value_custom = "rfid"[/b] is not a valid custom value.

4. If you have multiple Modbus devices then all devices with matching registers will be mapped to the same group address.


RE: Modbus mappings automation - pawel200388 - 21.07.2025

Hello admin,
thank you for your fast response. This code is part of a larger solution, in which in the first step I add group addresses, in the second I create a modbus device and attach a status object to it, and in the third I map selected points. It's a kind of "wizard" for my customers.


1. Ok, perfect. I changed it to:

Code:
(...)
  if valueBitmask ~= nil then
    sql = string.format(
      "SELECT id FROM modbus_mapping WHERE type='%s' AND address=%d AND value_bitmask='%s'",
      regType, regNum, valueBitmask
    )
  else
    sql = string.format(
      "SELECT id FROM modbus_mapping WHERE type='%s' AND address=%d",
      regType, regNum
    )
  end
(...)
local rows = db:getall(sql)
and it works smootly.

2. In fact I tried it as a hex. Now I have conversions, so both versions are OK Wink

3. I know, it was temporary. It's a kind of note that shows me where changes in the database have been saved and where they haven't.

4. Unfortunately I know. For now 1 device is enough, but in the future I'l have to rebuild the code to support more modbus devices. I assume I'll use the device column somehow.

Lastly...
5. Is there any simple way to clear modbus_mapping table? Smile I have some rubbish left there.
6. As I can see modbus doesn't start on its own. For now my solution was to automatically reboot it, but maybe there is other way?


RE: Modbus mappings automation - admin - 21.07.2025

5. Run this once:
Code:
db:query('DELETE FROM modbus_mapping')

6. You can send reload signal to Modbus daemon after making changes to the modbus_mapping DB table:
Code:
pid = os.checkproc('gs-modbus')
if pid then
  os.kill(pid, signal.SIGUSR1)
end