Logic Machine Forum
TCP Socket Connection for Legrand - 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: TCP Socket Connection for Legrand (/showthread.php?tid=2068)

Pages: 1 2


RE: TCP Socket Connection for Legrand - a455115 - 20.04.2022

Thank you very much, now it looks much more hopeful. But is there still a problem?




RE: TCP Socket Connection for Legrand - admin - 20.04.2022

Increase socket timeout by changing sock:settimeout(1) to sock:settimeout(5)


RE: TCP Socket Connection for Legrand - a455115 - 21.04.2022

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.


RE: TCP Socket Connection for Legrand - admin - 22.04.2022

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.


RE: TCP Socket Connection for Legrand - a455115 - 26.04.2022

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?


RE: TCP Socket Connection for Legrand - a455115 - 14.06.2022

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



RE: TCP Socket Connection for Legrand - admin - 15.06.2022

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/documentation/open-web-net-for-myhome/


RE: TCP Socket Connection for Legrand - a455115 - 23.06.2022

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?


RE: TCP Socket Connection for Legrand - admin - 27.06.2022

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()



RE: TCP Socket Connection for Legrand - a455115 - 28.06.2022

(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!


RE: TCP Socket Connection for Legrand - a455115 - 31.08.2022

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



RE: TCP Socket Connection for Legrand - admin - 31.08.2022

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.


RE: TCP Socket Connection for Legrand - a455115 - 01.09.2022

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.


RE: TCP Socket Connection for Legrand - a455115 - 07.10.2022

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?


RE: TCP Socket Connection for Legrand - admin - 07.10.2022

Try this code again: https://forum.logicmachine.net/showthread.php?tid=2068&pid=25762#pid25762
Make sure that the password contains only numbers otherwise the script will fail.


RE: TCP Socket Connection for Legrand - a455115 - 11.10.2022

(07.10.2022, 06:40)admin Wrote: Try this code again: https://forum.logicmachine.net/showthread.php?tid=2068&pid=25762#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.