Example: LM2 as TCP server for external requests

Task

On each value change for object ’1/1/1′, send TCP messages to all connected external TCP clients.

UDP client function

The following function has to be added into Scripting -> Tools -> User function library.
It will forward each message received to UDP server which will send it to all connected TCP clients.

  1. function udpsend(message)
  2. require('socket')
  3.  
  4. local client = socket.udp()
  5. -- upd client ready, send to local port 23456
  6. if client then
  7. client:sendto(message, '127.0.0.1', 23456)
  8. client:close()
  9. end
  10. end

Resident script – server handler

Add the following resident script with Sleep interval 0.
It defines TCP server and UDP server. Connection can be established when TCP client sends message “HELLO”, TCP server/LM2 will respond with “HELLO YOU TOO”.

  1. -- init server handler
  2. if not ready then
  3. require('copas')
  4.  
  5. -- list of client sockets
  6. clients = {}
  7.  
  8. -- incoming data handler
  9. function datahandler(sock, data)
  10. local ip, port
  11. ip, port = sock:getpeername()
  12. alert('[server] data from %s:%d - %s', ip, port, data)
  13.  
  14. -- send reply
  15. if data == 'HELLO' then
  16. sock:send('HELLO TO YOU\r\n')
  17. end
  18. end
  19.  
  20. -- connection handler
  21. function connhandler(sock)
  22. -- enable keep-alive to check for disconnect events
  23. sock:setoption('keepalive', true)
  24.  
  25. local ip, port, data, err, id
  26.  
  27. -- get ip and port from socket
  28. ip, port = sock:getpeername()
  29.  
  30. -- client id
  31. id = string.format('%s:%d', ip, port)
  32.  
  33. alert('[server] connection from %s', id)
  34.  
  35. -- save socket reference
  36. clients[ id ] = sock
  37.  
  38. -- main reader loop
  39. while true do
  40. -- wait for single line of data (until \n, \r is ignored)
  41. data, err = copas.receive(sock, '*l')
  42.  
  43. -- error while receiving
  44. if err then
  45. alert('[server] closed connection from %s:%d', ip, port)
  46. -- remove socket reference
  47. clients[ id ] = nil
  48. return
  49. end
  50.  
  51. -- handle data frame
  52. datahandler(sock, data)
  53. end
  54. end
  55.  
  56. -- bind to port 12345
  57. tcpserver = socket.bind('*', 12345)
  58.  
  59. -- error while binding, try again later
  60. if not tcpserver then
  61. os.sleep(5)
  62. error('[server] error: cannot bind')
  63. end
  64.  
  65. -- set server connection handler
  66. copas.addserver(tcpserver, connhandler)
  67.  
  68. -- create local udp server on port 23456
  69. udpserver = socket.udp()
  70. udpserver:setsockname('127.0.0.1', 23456)
  71. udpserver:settimeout(0.1)
  72.  
  73. ready = true
  74. end
  75.  
  76. -- perform server tasks for one second (5 x (0.1 + 0.1))
  77. for i = 1, 5 do
  78. message = udpserver:receive()
  79.  
  80. -- got message from udp, send to all active clients
  81. if message then
  82. for id, sock in pairs(clients) do
  83. sock:send(message .. '\r\n')
  84. end
  85. end
  86.  
  87. copas.step(0.1)
  88. end

Event-based program

Event-based script will monitor the object ’1/1/1′, if it is switched on, “Lamp is ON” is sent to all TCP clients currently connected to Logic Machine 2 TCP server, if lamp is switched off – “Lamp is OFF”.

  1. value = knxdatatype.decode(event.datahex, dt.bool)
  2. udpsend('Lamp is' .. (value and 'ON' or 'OFF'))