LM2 as TCP server for external requests
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.
- function udpsend(message)
- require('socket')
-
- local client = socket.udp()
- -- upd client ready, send to local port 23456
- if client then
- client:sendto(message, '127.0.0.1', 23456)
- client:close()
- end
- 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”.
- -- init server handler
- if not ready then
- require('copas')
-
- -- list of client sockets
- clients = {}
-
- -- incoming data handler
- function datahandler(sock, data)
- local ip, port
- ip, port = sock:getpeername()
- alert('[server] data from %s:%d - %s', ip, port, data)
-
- -- send reply
- if data == 'HELLO' then
- sock:send('HELLO TO YOU\r\n')
- end
- end
-
- -- connection handler
- function connhandler(sock)
- -- enable keep-alive to check for disconnect events
- sock:setoption('keepalive', true)
-
- local ip, port, data, err, id
-
- -- get ip and port from socket
- ip, port = sock:getpeername()
-
- -- client id
- id = string.format('%s:%d', ip, port)
-
- alert('[server] connection from %s', id)
-
- -- save socket reference
- clients[ id ] = sock
-
- -- main reader loop
- while true do
- -- wait for single line of data (until \n, \r is ignored)
- data, err = copas.receive(sock, '*l')
-
- -- error while receiving
- if err then
- alert('[server] closed connection from %s:%d', ip, port)
- -- remove socket reference
- clients[ id ] = nil
- return
- end
-
- -- handle data frame
- datahandler(sock, data)
- end
- end
-
- -- bind to port 12345
- tcpserver = socket.bind('*', 12345)
-
- -- error while binding, try again later
- if not tcpserver then
- os.sleep(5)
- error('[server] error: cannot bind')
- end
-
- -- set server connection handler
- copas.addserver(tcpserver, connhandler)
-
- -- create local udp server on port 23456
- udpserver = socket.udp()
- udpserver:setsockname('127.0.0.1', 23456)
- udpserver:settimeout(0.1)
-
- ready = true
- end
-
- -- perform server tasks for one second (5 x (0.1 + 0.1))
- for i = 1, 5 do
- message = udpserver:receive()
-
- -- got message from udp, send to all active clients
- if message then
- for id, sock in pairs(clients) do
- sock:send(message .. '\r\n')
- end
- end
-
- copas.step(0.1)
- 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”.
- value = knxdatatype.decode(event.datahex, dt.bool)
- udpsend('Lamp is' .. (value and 'ON' or 'OFF'))