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.

Source code    
  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”.

Source code    
  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”.

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