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.

TCP Socket Connection for Legrand
#21
Thank you very much, now it looks much more hopeful. But is there still a problem?

Reply
#22
Increase socket timeout by changing sock:settimeout(1) to sock:settimeout(5)
Reply
#23
Thank you administrator!

So already in the alarms the connection is ok.

How do I see the messages from the bus in LM? Because at the moment I only have * # * 1 ##, but not what's going on online. My goal is to transfer all lamps and thermostats to LM for easier and more beautiful operation. That is, I need to be able to read and change their condition.

I apologize for the stupid questions, but I'm still new to writing scripts.
Reply
#24
After the connection is open you need to call read and parse the incoming data. For sending commands a separate script might be needed because there are two session types - command (*99*0##) and event (*99*1##). Unfortunately it's quite hard to make a full example without being able to test it on a real device.
Reply
#25
Okay, I get it.

I used the sample TCP code:
Code:
function read(sock)
  local buf = {}

  while true do
    local ch, err = sock:receive(1)

    if ch then
      local pr = buf[ #buf ]

      buf[ #buf + 1 ] = ch

      if ch == '#' and pr == '#' then
        break
      end

    else
      return nil, err
    end
  end

  local ret = table.concat(buf)
  log(ret)
  return ret
end




-- init socket
if not sock then
  require('socket')

  sock, err = socket.connect('192.168.1.247', 20000)

  -- set timeout to 1 second
  if sock then
    sock:settimeout(1)
  -- error opening connection, log error and wait before reconnecting 
  else
    error(err)
    sleep(5)
  end
end

-- socket handler
if sock then   

sock:send('*99*1##')
 
 
 
--data = sock:receive(14)
   res, err = read(sock)
 
 
 
--sock:send('*#1*12##')
-- log('check')
-- sock:send('*1*1*12##')
  -- got data, log it
  if data then
    log(data)
  end
end

 and I'm currently getting this:
* # 4 * 1 * 0 * 0229 ## in log.
Which means that the temperature of thermostat 1 is 22.9 degrees. How to separate the digit with the code 1 to be address 32/1/1 and write the value 22.9 in it? How do I separate receiving and sending commands so that it works properly?
Reply
#26
Hi, I made several attempts to control the MX200 with a script, but unfortunately failed. I have the following commands on the line:

Code:
MH200
26.04.2022 19:53:58    
* string: *1*9*11##    90%
    
    
MH200
26.04.2022 19:54:15    
* string: *1*1000#0*11##    OK
    
    
MH200
26.04.2022 19:54:15    
* string: *1*0*11##    OFF

could you help me to bind them in a script so that I can recognize them on arrival and bind them to the respective objects and accordingly if the value of the object changes I send the command back to the gateway?
This is the code I use to get them in the log:
Code:
function read(sock)
  local buf = {}

  while true do
    local ch, err = sock:receive(1)

    if ch then
      local pr = buf[ #buf ]

      buf[ #buf + 1 ] = ch

      if ch == '#' and pr == '#' then
        break
      end

    else
      return nil, err
    end
  end

  local ret = table.concat(buf)
  log(ret)
  return ret
end




-- init socket
if not sock then
  require('socket')

  sock, err = socket.connect('192.168.1.247', 20000)

  -- set timeout to 1 second
  if sock then
    sock:settimeout(1)
  -- error opening connection, log error and wait before reconnecting 
  else
    error(err)
    sleep(5)
  end
end

-- socket handler
if sock then   

sock:send('*99*1##')

   res, err = read(sock)
 

  if data then
    log(data)
  end
end
Reply
#27
Use this. Changing mapping will require full script restart via disable/enable.
Code:
if not sock then
  mapping = {
    ['11'] = '1/1/11',
  }

  function parselighting(what, where)
    local addr = mapping[ where ]
    what = tonumber(what) or -1

    if addr and 0 <= what and what <= 10 then
      grp.checkwrite(addr, what * 10)
    end
  end

  function parse(msg)
    local who, what, where = unpack(msg:split('*'))
    who = tonumber(who)

    -- lighting
    if who == 1 then
      parselighting(what, where)
    end
  end

  function read(sock)
    local buf = {}

    while true do
      local ch, err = sock:receive(1)

      if ch then
        local pr = buf[ #buf ]

        buf[ #buf + 1 ] = ch

        if ch == '#' and pr == '#' then
          break
        end

      else
        return nil, err
      end
    end

    if #buf > 0 and buf[ 1 ] == '*' then
      return table.concat(buf, '', 2, #buf - 2)
    end
  end

  sock = require('socket').tcp()
  sock:settimeout(1)

  res, err = sock:connect('192.168.1.247', 20000)

  if res then
    sock:send('*99*1##')
  else
    log('connect failed', err)

    sock:close()
    sock = nil
    os.sleep(1)
  end
end

-- socket handler
if sock then    
  res, err = read(sock)

  if res then
    parse(res)
  elseif err == 'closed' then
    sock:close()
    sock = nil
  end
end

This example partially implements parsing of lighting type messages (off and dimming).
Docs for all types: https://developer.legrand.com/documentat...or-myhome/
Reply
#28
Thank you so much!

 It works perfectly, but now how can I send commands to the gateway when changing the object in a logic machine?
Reply
#29
You need a separate socket connection for commands. You also need to send another init sequence: *99*0##.
This example should control light point 11 by converting 0..100% value to 0..10. There's some extra logging to check if the message flow is correct. Remove it when the script is working properly.
Code:
value = event.getvalue()
value = math.ceil(value / 10)

cmd = '*1*' .. value .. '*11##'

sock = require('socket').tcp()
sock:settimeout(1)

res, err = sock:connect('192.168.1.247', 20000)

if res then
  sock:send('*99*0##')
  
  res, err = sock:receive(6) -- receive ACK
  log('receive 1', res, err)

  res, err = sock:send(cmd)
  log('send', res, err)

  res, err = sock:receive(6) -- receive result ACK/NACK
  log('receive 2', res, err)
else
  log('connect failed', err)
end

sock:close()
Reply
#30
(27.06.2022, 12:15)admin Wrote: You need a separate socket connection for commands. You also need to send another init sequence: *99*0##.
This example should control light point 11 by converting 0..100% value to 0..10. There's some extra logging to check if the message flow is correct. Remove it when the script is working properly.
Code:
value = event.getvalue()
value = math.ceil(value / 10)

cmd = '*1*' .. value .. '*11##'

sock = require('socket').tcp()
sock:settimeout(1)

res, err = sock:connect('192.168.1.247', 20000)

if res then
  sock:send('*99*0##')
 
  res, err = sock:receive(6) -- receive ACK
  log('receive 1', res, err)

  res, err = sock:send(cmd)
  log('send', res, err)

  res, err = sock:receive(6) -- receive result ACK/NACK
  log('receive 2', res, err)
else
  log('connect failed', err)
end

sock:close()

Works perfectly!

Thank you very much for the help!
Reply
#31
Hello Admin,

Would you help me to refactor the code so that it can use all the features of Open web net ? I tried to redo it myself for the temperature, but I'm sure it's not the right way since the string is different there.

Code:
if not sock then
  mappingtemp = {
    ['1'] = '1/1/1',
    ['2'] = '1/1/2',

  }
  mapping = {
   
    ['3'] = '1/1/3',
    ['4'] = '1/1/4',
    ['5'] = '1/1/5',
    ['6'] = '1/1/6',
    ['7'] = '1/1/7',
    ['8'] = '1/1/8',
    ['9'] = '1/1/9',
    ['10'] = '1/1/10',
    ['11'] = '1/1/11',
    ['12'] = '1/1/12',
    ['13'] = '1/1/13',
    ['14'] = '1/1/14',
    ['15'] = '1/1/15',
    ['16'] = '1/1/16',
    ['17'] = '1/1/17',
    ['22'] = '1/1/22',
    ['23'] = '1/1/23',
    ['51'] = '1/1/51',
    ['0215'] = '1/1/52',
  }
 
   function parselighting(what, where)
    log("Ok")
    local addr = mapping[ where ]
    what = tonumber(what) or -1

    if addr and 0 <= what and what <= 10 then
      grp.checkwrite(addr, what)
    end
  end
 
 
 
 
  function parsetemperature(where, value)
    local addr = mappingtemp[ where ]
    log(where)
    value = tonumber(value) or -1

    if addr and 0 <= value and value <= 4050 then
      value = value * 0.1
      grp.checkwrite(addr, value)
      log("done",value)
    end
  end

 
 
 
 
 
  function parse(msg)
    log (msg)
    length = string.len(msg)
   
    if length == 11 then
    log("length",length)
    local who, where, dimension, value = unpack(msg:split('*'))
    if who == "#4" then
    who = string.sub(who,2,2)
    who = tonumber(who)
    parsetemperature(where, value)
end
    end
     if length == 6 then
      log("length",length)
       local who, what, where = unpack(msg:split('*'))
            who = tonumber(who)
       -- lighting
        if who == 1 then
      parselighting(what, where)
      log(what)
      log(where)
    end
  end
   
  end

  function read(sock)
    local buf = {}

    while true do
      local ch, err = sock:receive(1)

      if ch then
        local pr = buf[ #buf ]

        buf[ #buf + 1 ] = ch

        if ch == '#' and pr == '#' then
          break
        end

      else
        return nil, err
      end
    end

    if #buf > 0 and buf[ 1 ] == '*' then
      return table.concat(buf, '', 2, #buf - 2)
    end
  end

  sock = require('socket').tcp()
  sock:settimeout(1)

  res, err = sock:connect('192.168.1.195', 20000)

  if res then
    sock:send('*99*1##')
  else
    log('connect failed', err)

    sock:close()
    sock = nil
    os.sleep(1)
  end
end

-- socket handler
if sock then   
  res, err = read(sock)

  if res then
    log(res)
    parse(res)
  elseif err == 'closed' then
    sock:close()
    sock = nil
  end
end
Reply
#32
Try replacing the parse function with this:
Code:
function parse(msg)
  local chunks = msg:split('*')
  local who = table.remove(chunks, 1)

  if who == '#1' then
    local what, where = unpack(chunks)
    parselighting(what, where)
  elseif who == '#4' then
    local where, dimension, value = unpack(chunks)
    parsetemperature(where, value)
  end
end
If it does not work then provide logs of the received messages.
Reply
#33
Thanks Admin!

With a slight modification it works perfectly. But I have another problem - the system runs fast for about a day and then starts responding after about 10 seconds (turning on the lights with the first code). I try with OpenWebNet_Client from my PC and it works fast. When I changed the IP on the MH200N it worked quickly again for about a day. Restarting LM or anything else makes no difference. The only difference is that through OpenWebNet_Client I log in with a password, and LM is on a password-free IP. Could there be some communication left open that would initiate the delay? Do you have any other idea? I know it's hard when you don't have access to a working installation, but at least if you could give me some pointers on how and where to look for it.
Reply
#34
Hi Admin,

I still have no progress on the case. Can you help me refactor the code so that I can log in with a username and password?
Reply
#35
Try this code again: https://forum.logicmachine.net/showthrea...2#pid25762
Make sure that the password contains only numbers otherwise the script will fail.
Reply
#36
(07.10.2022, 06:40)admin Wrote: Try this code again: https://forum.logicmachine.net/showthrea...2#pid25762
Make sure that the password contains only numbers otherwise the script will fail.

Hello,

The code works! It manages to log in, now I have to combine it with the other one so that it can also control the lighting.
Reply


Forum Jump: