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/ip connect and maintain connection
#1
I am trying to place a resident script to connect to an ip address, monitor connection and reconnect if connection is lost.
I am reading and watching every tutorial i can find and am slowly getting more understanding but need others help with this.

I am after some guidance in the implementation of a TCP/ip connection to third party device (Symetrix DSP, control protocol same as control4, amx, crestron, lutron).
I have connection working between both the SHAC and the Symetrix DSP, as in I can ping it with a response through the "Network Utilities"
I have full control of Symetrix working through PuTTY terminal and now need to implement scripting to send, and manage received data.

Can anyone share with me scripting that will build this connection, maintain this connection, reconnect if device goes offline then returns online..
I have found multiple examples of this but am not getting much luck with connection or how to monitor if the connection is alive.


Code:
local socket = require("socket")
local host, port = "192.168.1.246", 48631
local tcp = assert(socket.tcp())


Once i have this connection up and running I need to build scripting to send controls to and receive pushed controls back to update GA's in the SHAC.

Control protocol info from Symetrix document shown below.

The Control Protocol is a text-based (ASCII string) protocol. Commands are sent with simple character strings with terms separated by spaces and completed with a carriage return character <CR> (ASCII code decimal 13). The general form for commands is:
<COMMAND> <PARAMETER1> <PARAMETER2> … <CR>

When in PuTTY if i send the command            CS 1 65535 <CR>        
I get Controller Set "CS" to controller number "1" set to maximum "65535" (all as expected) with a response of ACK.

Can I send this same data through a LUA script? or does it need to be converted to another format?
Reply
#2
Use this resident script (sleep time = 0) as a starting point:
Code:
-- socket connected
if connected then
  -- send command
  sock:send('CS 1 65535\r')

  -- read until one line received or error occured
  while true do
    char, err = sock:receive(1)

    -- error while receiving, timeout or closed socket
    if err then
      -- remote server closed connection, reconnect
      if err == 'closed' then
        connected = false
        alert('[tcp-sock] connection closed')
        os.sleep(1)
      end

      break
    -- end of line, parse buffer
    elseif char == '\r' then
      data = table.concat(buffer)
      log(data)
      buffer = {}

      -- wait some time before next request
      os.sleep(1)

      break
    -- other char, add to buffer
    else
      buffer[ #buffer + 1 ] = char
    end
  end
-- first call or previously disconnected
else
  -- close previous connection when disconnected
  if sock then
    sock:close()
    sock = nil
  end

  -- create tcp socket
  sock = require('socket').tcp()
  sock:settimeout(1)
  connected, err = sock:connect('192.168.0.9', 80)

  -- connect ok, reset buffer
  if connected then
    alert('[tcp-sock] connection ok')
    buffer = {}
  -- error while connecting
  else
    alert('[tcp-sock] connection failed: %s', err)
    os.sleep(5)
  end
end
Reply
#3
Thank you so much, now i know that this will be achievable and I can manage everything from my SHAC.

next question can i place a variable parameter into a sockConfusedend??
as in 

value = GetCBusLevel(0,  127, 10) --0-255

value * (65535/255)

value * 257


example

  -- send command
  sockConfusedend('CS 34 value*257 \r')

this is not working, how would i go about implementing this variable number into the "socket send"
Reply
#4
Like this:
Code:
value = GetCBusLevel(0,  127, 10)
command = 'CS 34 ' .. (value * 257) .. '\r'
sock:send(command)
Reply
#5
(21.10.2023, 10:56)Erwin van der Zwart Wrote: Like this:
Code:
value = GetCBusLevel(0,  127, 10)
command = 'CS 34 ' .. (value * 257) .. ‘\r'
sock:send(command)

I'm getting a error

Lua syntax error at line 9: unexpected symbol near '\'

How do I get "value x 257" into "command" so that it can be sent
Reply
#6
(21.10.2023, 22:16)Azar Wrote:
(21.10.2023, 10:56)Erwin van der Zwart Wrote: Like this:
Code:
value = GetCBusLevel(0,  127, 10)
command = 'CS 34 ' .. (value * 257) .. ‘\r'
sock:send(command)

I'm getting a error

Lua syntax error at line 9: unexpected symbol near '\'

How do I get "value x 257" into "command" so that it can be sent
Hi,
There is an error in the char ` use '.
Best regards Cristian
Reply
#7
(22.10.2023, 10:21)CristianAgata Wrote:
(21.10.2023, 22:16)Azar Wrote:
(21.10.2023, 10:56)Erwin van der Zwart Wrote: Like this:
Code:
value = GetCBusLevel(0,  127, 10)
command = 'CS 34 ' .. (value * 257) .. ‘\r'
sock:send(command)

I'm getting a error

Lua syntax error at line 9: unexpected symbol near '\'

How do I get "value x 257" into "command" so that it can be sent
Hi,
There is an error in the char ` use '.
Best regards Cristian

Hi Cristian, would you kindly explain in more detail? I'm not sure what you mean! Are you pointing to the end of the second line ? Just prior to the backslash?
Reply
#8
(22.10.2023, 11:45)Azar Wrote:
(22.10.2023, 10:21)CristianAgata Wrote:
(21.10.2023, 22:16)Azar Wrote:
(21.10.2023, 10:56)Erwin van der Zwart Wrote: Like this:
Code:
value = GetCBusLevel(0,  127, 10)
command = 'CS 34 ' .. (value * 257) .. ‘\r'
sock:send(command)

I'm getting a error

Lua syntax error at line 9: unexpected symbol near '\'

How do I get "value x 257" into "command" so that it can be sent
Hi,
There is an error in the char ` use '.
Best regards Cristian

Hi Cristian, would you kindly explain in more detail? I'm not sure what you mean!°
In your code if I m looking good before the /r' there's this char "`" and it is wrong. You must change with this " ' ".
Best regards Cristian
Reply
#9
Oeps.. responding with iOS on iPhone does that but indeed ‘ must be '

Corrected it in my original post
Reply
#10
Code:
-- socket connected
if connected then
 
 
  -- Get level of the Volume control group in the Symetrix Control 127 application on the local network
value = GetCBusLevel(0,  127, 10)
 
  -- Convert level to command
--command = 'cs 34' ..(value*257).. cr
 
command = 'CS 34 '..(value * 257).. '\r'

 
    -- send command
sock:send (command)

  -- read until one line received or error occured
  while true do
    char, err = sock:receive(1)

    -- error while receiving, timeout or closed socket
    if err then
      -- remote server closed connection, reconnect
      if err == 'closed' then
        connected = false
        alert('[tcp-sock] connection closed')
        os.sleep(1)
      end

      break
    -- end of line, parse buffer
    elseif char == '\r' then
      data = table.concat(buffer)
      log(data)
      buffer = {}

      -- wait some time before next request
      os.sleep(1)

      break
    -- other char, add to buffer
    else
      buffer[ #buffer + 1 ] = char
    end
  end
-- first call or previously disconnected
else
  -- close previous connection when disconnected
  if sock then
    sock:close()
    sock = nil
  end

  -- create tcp socket
  sock = require('socket').tcp()
  sock:settimeout(1)
  connected, err = sock:connect('192.168.1.246', 48631)

  -- connect ok, reset buffer
  if connected then
    alert('[tcp-sock] connection ok')
    buffer = {}
  -- error while connecting
  else
    alert('[tcp-sock] connection failed: %s', err)
    os.sleep(5)
  end
end
All is good now, conversion from cbus 255 to control 65535 is working,  
This script continues to send command at every 1 second interval is there any way i can change this so that it only sends socket command apon a new change of cbus level value. similar to an event script that waits for an event before acting?
Reply
#11
Just add a if condition like this:
Code:
if previousvalue ~= value then
  -- send command
  sock:send (command)
  previousvalue == value
end
But if the value is not change often i would make it event based, initiate the connection, write the command and close the connection..
Reply
#12
(28.10.2023, 08:25)Erwin van der Zwart Wrote: Just add a if condition like this:
Code:
if previousvalue ~= value then
  -- send command
  sock:send (command)
  previousvalue == value
end
But if the value is not change often i would make it event based, initiate the connection, write the command and close the connection..
I've decided to go to an event script but cant get this to work.
Event script by Keyword: Symetrix.
all GA's with keyword "Symetrix" also have there control comand number assigned to them by keyword " SYM=### " I'm trying to get the script to insert the control number into the "CS" Command Send line .
I'm getting a log of

 * string: Error: sym=address tag missing
Code:
    local value = event.getvalue()
    local dest = event.dst

    local grps = GetCBusByKW('Symtrix', 'or')
    local k, v, alias, net, app, group
    local addr = ''
    local buffer = {}
log(grps)
    for k, v in pairs(grps) do
      alias = table.concat(v.address, '/')
      if alias == dest then
        local tags = v.keywords
     --log(tags)
        local t
        for _, t in ipairs(tags) do
          local tp = string.split(t, '=')
          tp[1] = trim(tp[1])
          if tp[2] then
            tp[2] = trim(tp[2])
            if tp[1] == 'sym' then
              addr = tp[2] -- Get device address
              break
            end
          end
        end
        break
      end
    end

    if addr ~= '' then
      -- create tcp socket
      local sock = require('socket').tcp()
      sock:settimeout(1)
      local connected, err = sock:connect('192.168.1.246', 48631)

      -- connect ok
      if connected then
        alert('[tcp-sock] connection ok')
      -- error while connecting
      else
        log('[tcp-sock] connection failed: '..err)
        sock:close()
        do return end
      end

      local command = 'CS '..addr..' '..(value * 257).. '\r'

      -- send command
      sock:send (command)

      local sent = socket.gettime()
      local timeout = 5

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

        -- error while receiving, timeout or closed socket
        if err then
          -- remote server closed connection
          log('[tcp-sock] connection closed'..err)
          break
        -- end of line, parse buffer
        elseif char == '\r' then
          local data = table.concat(buffer)
          log(data)
          break
        -- other char, add to buffer
        else
          buffer[ #buffer + 1 ] = char
        end

        if socket.gettime() - sent > 5 then
          log('Timeout receiving data')
          break
        end
      end
      sock:close()
    else
      log('Error: sym=address tag missing')
    end

   
Reply
#13
Try using this:
Code:
tags = grp.gettags(event.dst)

for _, tag in ipairs(tags) do
  addr = tag:match('SYM=(%d+)')
  
  if addr then
    break
  end
end

log(addr)
if addr then
  -- send TCP message
end

Note that tags are case-sensitive.
Reply


Forum Jump: