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 slave with LM
#1
Hi all,

I'm scripting a process to simulate power meters with luamodbus functions, and it works wery well when I read all my registers with ModbusPoll scanner. 

But using my script with a real Modbus master product, I have a lot of "connexion errors" (printed by the master).

@IP, port and slaveId are corrects...

Any idea about this ?

Thank's in advance.
All my best.

Dominique
Reply
#2
Which script do you use?
------------------------------
Ctrl+F5
Reply
#3
(17.01.2023, 12:55)Daniel Wrote: Which script do you use?

Code:
--------------------------------------------------------------------------------
-- Wiser For Knx : Modbus esclave TCP/IP
--------------------------------------------------------------------------------
-- Simulateur de centrale de mesure pour EcoStruxure EV Charging Expert
--------------------------------------------------------------------------------
--
-- Modèle : iEM3x5x pour Bornes de recharge PRO AC
--
--------------------------------------------------------------------------------
-- v1.2 du 17/01/2023 - D.Barboyon
--------------------------------------------------------------------------------
-- (c) Sigma Tec - 2023
--------------------------------------------------------------------------------

------------- Paramétrage ------------------------------------------------------
idPort        = 503 -- No de port Modbus/TCP        - toujours >= 502
idSlave       = 3   -- No esclave Modbus/TCP        - toujours >= 2
PMname        = "iEM3155-B2"    -- nom du compteur - long <= 14 car
--------------------------------------------------------------------------------

idGroup       = idPort-500        -- idGroup/slaveNum/x

idSteMapping1 = 0
idSteMapping2 = 0
idSetMapping3 = 6502
idSteMapping4 = 6502

-- ---------------------------------------------------------------------
-- Table des objets Wiser For Knx et registres associés
-- ---------------------------------------------------------------------


groupList = {
  { addr = idGroup, datatype="string"       , name=PMname        ,reg=idPort    , unit=""    , tags="-"},
  { addr = idGroup, datatype="uint16"          , name="I1"          ,reg="3000"    , unit="A"   , tags="modbus"},
  { addr = idGroup, datatype="uint16"       , name="I2"           ,reg="3002"    , unit="A"   , tags="modbus"},
  { addr = idGroup, datatype="uint16"          , name="I3"          ,reg="3004"    , unit="A"   , tags="modbus"},
  { addr = idGroup, datatype="uint16"         , name="P1"           ,reg="3054"    , unit="kW"  , tags="modbus"},
  { addr = idGroup, datatype="uint16"          , name="P2"          ,reg="3056"    , unit="kW"  , tags="modbus"},
  { addr = idGroup, datatype="uint16"       , name="P3"           ,reg="3058"    , unit="kW"  , tags="modbus"},
  { addr = idGroup, datatype="uint16"          , name="P"          ,reg="3060"    , unit="kW"  , tags="modbus"},
  { addr = idGroup, datatype="uint32"       , name="ET"           ,reg="3204"    , unit="kWh" , tags="modbus"},
  { addr = idGroup, datatype="bool"         , name="PH1"           ,reg="true"    , unit=""    , tags="-"},
  { addr = idGroup, datatype="bool"         , name="PH2"           ,reg="true"    , unit=""    , tags="-"},
  { addr = idGroup, datatype="bool"         , name="PH3"           ,reg="true"    , unit=""    , tags="-"},
  { addr = idGroup, datatype="bool"         , name="BTN"           ,reg="true"    , unit=""    , tags="-"},
  { addr = idGroup, datatype="unit16"        , name="CURSEUR"    ,reg="true"    , unit="A"   , tags="-"},
  { addr = idGroup, datatype="bool"         , name="BTN MONO"    ,reg="false"    , unit=""    , tags="-"},
  { addr = idGroup, datatype="bool"         , name="BTN TRI"     ,reg="true"    , unit=""    , tags="-"},
  { addr = idGroup, datatype="string"        , name="TYPE MONO-TRI"  ,reg="TRI"    , unit=""    , tags="-"},
  { addr = idGroup, datatype="bool"         , name="PHASE MONO"       ,reg="1"    , unit=""    , tags="-"},
  { addr = idGroup, datatype="uint16"          , name="I Phase AVG"      ,reg="3010"    , unit="A"   , tags="modbus"},
  { addr = idGroup, datatype="uint16"          , name="U Phase1"      ,reg="3028"    , unit="V"   , tags="modbus"},
  { addr = idGroup, datatype="uint16"          , name="U Phase2"      ,reg="3030"    , unit="V"   , tags="modbus"},
  { addr = idGroup, datatype="uint16"          , name="U Phase3"      ,reg="3032"    , unit="V"   , tags="modbus"},
  { addr = idGroup, datatype="uint16"          , name="U AVG"      ,reg="3036"    , unit="V"   , tags="modbus"},
  { addr = idGroup, datatype="uint16"          , name="P apparente"      ,reg="3076"    , unit="kVA" , tags="modbus"},
  { addr = idGroup, datatype="uint16"          , name="Fact Pu"      ,reg="3084"    , unit=""    , tags="modbus"},
  { addr = idGroup, datatype="uint16"          , name="Frequence"      ,reg="3110"    , unit="Hz"  , tags="modbus"},
  { addr = idGroup, datatype="uint32"          , name="QT E"          ,reg="3220"    , unit="kVAR", tags="modbus"},
  { addr = idGroup, datatype="uint16"       , name="QT P total"       ,reg="3068"    , unit="kVAR", tags="modbus"}
}        

-- Spécifique Pro AC : reg Modbus 6501 (uint16) = SlaveId obligatoire
------------------------------------------------------------------------
local proacSlaveReg = 6501

-- ---------------------------------------------------------------------
-- Gestion de la création des objets Wiser For Knx
-- ---------------------------------------------------------------------

function ST_grpCreate(STdatatype,STgroup,STname,STcomment,STunits,STtag)
------------------------------------------------------------------------
  grp.create({
      datatype     = STdatatype,
      address     = STgroup,
      name         = STname,
      comment     = STcomment,
      units         = STunits,
      tags         = { "EVCE", STname },
    })
end

-- Scan la table et crée les objets WFK si nécessaire
------------------------------------------------------------------------

for i, groupCurr in ipairs(groupList) do
  STgroup = groupCurr.addr.."/"..idSlave.."/"..i
 
  if i == 1 then   -- spécifique objet "nom de la centrale de mesure"
    nomGroupe = groupCurr.reg.."#"..idSlave
    valGroupe = groupCurr.name
    objGroupe = STgroup 
    -- Update objet "nom de la centrale de mesure"
    grp.write(objGroupe, valGroupe)    
  end
 
  if grp.find(STgroup) then
    --existe deja
  else  
    -- crée le groupe
    STdatatype       = groupCurr.datatype
    STname           = nomGroupe.."-"..groupCurr.name
    STcomment       = "-"
    STunits           = groupCurr.unit
    STtag           = groupCurr.tags
    ST_grpCreate(STdatatype,STgroup,STname,STcomment,STunits,STtag)
  end
end




-- -----------------------------------------------
-- Processus MaJ registres Modbus slave
-- -----------------------------------------------

if not mb then

  log("EVCE cyclic - Modbus #2 : starting mb")
 
  require('luamodbus')

  -->>>>>>>>>Modbus slave setting<<<<<<<<<<<<<<<<<<<<<<<<
  -- Modbus TCP
  ------------------------------------------------------
  mb = luamodbus.tcp()
  mb:open('0.0.0.0', idPort)
  ------------------------------------------------------ 

  -->>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 
 
  -- slave id
  mb:setslave(idSlave)
 
  -- init slave storage for coils, discrete inputs, holding registers and input registers
  mb:setmapping(idSetMapping3, idSetMapping2, idSetMapping3, idSetMapping4)
 
  --*****************************************************
  -- >>>>>>>>>>>Coil write callback<<<<<<<<<<<<<<<<<<<<<<
  mb:setwritecoilcb(function(coil, value)
        if coil == 0 then
            grp.write('0/0/12', value, dt.bool)
        else
            alert('coil: %d = %s', coil, tostring(value))
        end
  end)
  --*****************************************************
  -->>>>>>>>>>>Register write callback<<<<<<<<<<<<<<<<<<<
  mb:setwriteregistercb(function(register, value)
        if register == 0 then
            -- send value limited to 0..100
            grp.write('0/0/13', math.min(100, value), dt.scale)
        else
            alert('register: %d = %d', register, value)
        end
  end)
  --*****************************************************
 
 
  -- spécifique Pro Ac ----------------
  addRegister = proacSlaveReg 
  addRegister = addRegister -1
  mb:setregisters(addRegister, idSlave)
  -------------------------------------
  
  log("EVCE cyclic - Modbus #2 : END OF starting mb")
 
end

-- Scan la table et Maj des objets autres que Modbus slave
------------------------------------------------------------------------

for i, groupCurr in ipairs(groupList) do

    dataType    = groupCurr.datatype

    if dataType == "bool" and groupCurr.tags == "-" then
       nomGroupe = groupCurr.addr.."/"..idSlave.."/"..i
     
       if grp.find(nomGroupe) then
         -- groupe existe 
       else  
     grp.write(nomGroupe, groupCurr.reg)   
       end
     
    end
 
    if dataType == "string" and groupCurr.tags == "-" and i > 1 then
      nomGroupe        = groupCurr.addr.."/"..idSlave.."/"..i
      if grp.find(nomGroupe) then
        -- groupe existe 
      else  
    grp.write(nomGroupe, groupCurr.reg)   
      end   
    end
 
end

-- Scan la table et MaJ registres Modbus slave
------------------------------------------------------------------------
-- addr = idGroup, datatype="uint16"  , name="I1" ,reg="3000" , unit="A" , tags=""

for i, groupCurr in ipairs(groupList) do

  addRegister = groupCurr.reg
  dataTags    = groupCurr.tags
  dataType    = groupCurr.datatype
  nomGroupe   = groupCurr.addr.."/"..idSlave.."/"..i
 
  -- valeur courante de l'objet WFK
  value = grp.getvalue(nomGroupe) 
 
  if dataType == "uint16" and dataTags == "modbus" then
   
    addRegister = addRegister -1

    -- dt.float16, dt.float32, dt.int64, dt.int32
    raw = knxdatatype.encode(value, dt.float32).dataraw 

    r1 = raw:byte(1) * 0x100 + raw:byte(2)
    r2 = raw:byte(3) * 0x100 + raw:byte(4)
        
    mb:setregisters(addRegister, r1, r2)
        
    --mb:setregisters(addRegister,   r1)
    --mb:setregisters(addRegister+1, r2)

  end
 
  if dataType == "uint32" and dataTags == "modbus" then

    addRegister = addRegister -1   

    -- dt.float16, dt.float32, dt.int64, dt.int32
    raw = knxdatatype.encode(value, dt.int64).dataraw 

    r1 = raw:byte(1) * 0x100 + raw:byte(2)
    r2 = raw:byte(3) * 0x100 + raw:byte(4)
    r3 = raw:byte(5) * 0x100 + raw:byte(6)
    r4 = raw:byte(7) * 0x100 + raw:byte(8)

    mb:setregisters(addRegister, r1, r2, r3, r4)
   
    --mb:setregisters(addRegister,   r1)
    --mb:setregisters(addRegister+1, r2)
    --mb:setregisters(addRegister+2, r3)
    --mb:setregisters(addRegister+3, r4)  
   
  end 

end

mb:handleslave()
Reply
#4
Consider using this script instead: https://forum.logicmachine.net/showthrea...6#pid27726
Your current script does a lot of busy polling via grp.getvalue after each slave step which can lead to timeouts.
Reply
#5
(17.01.2023, 13:35)admin Wrote: Consider using this script instead: https://forum.logicmachine.net/showthrea...6#pid27726
Your current script does a lot of busy polling via grp.getvalue after each slave step which can lead to timeouts.

It seemed to me that the problem was there. Thank you for this new version that I will try immediately.

Many thank's too for your help.
Dominique
Reply


Forum Jump: