LogicMachine as gateway between RTI and KNX
Example: LogicMachine as gateway between RTI and KNX
Task
How to realize bi-directional communication between RTI T2-Cs+ universal controller and KNX bus devices?
RTI XP-6 driver
Data exchange between XP-6 controller and LogicMachine is realized with the driver (LogicMachine.rtidriver). In driver settings you need to specify IP address of LogicMachine and set up group addresses which status will be displayed on remotes.
Function for LogicMachine
The following function should be added in Scripting -> Common functions.
- function updatestring(number)
- -- update of string
- if number == '1' then
- local value = grp.getvalue('3/0/1') —temperature request of the room
- local t = tostring(value)
- return string.format('%.1f', t) —converting to string to show on display
- End
- -- numbers of strings are set in interval from 1 to 250
- end
-
- function updatebutton(number)
- return false
- end
-
- function pushbutton(number)
- -- processing of button press
- if number == '1' then
- local value = grp.getvalue('3/0/2')
- if value < 37 then value = value + 0.1 — Chnage room temperature end grp.write('3/0/4', value) elseif number == '2' then local value = grp.getvalue('3/0/2') if value > 7 then
- value = value - 0.1 -- Chnage room temperature
- end
- grp.write('3/0/4', value)
- end
- -- Buttons numbers are set in interval from 1 to 250
- end
-
- function sendstring(address,value)
- local t = tostring(value)
- local number = nil
- if address == '3/0/1' then
- number = 1
- end
- if number then
- udpsend("STRING",number,"STRING",string.format('%.1f', t))
- end
- end
-
- function sendaddress(address,datatype,value)
- udpsend("WRITEADDRESS",address,datatype,value)
- end
-
- function udpsend(command,address,datatype,value)
- require('socket')
-
- local client = socket.udp()
- local message = '#RTI_Control#@'..command..'@%%'..address..'%%$'..datatype..'$~'..value..'~\r\n'
-
- -- upd client ready, send to local port 12345
- if client then
- client:sendto(message, '127.0.0.1', 12345)
- client:close()
- end
- end
Resident script – server realization
Add the following script with Sleep interval “0”
- 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()
-
- _,_,command,address,datatype,value = string.find(data, "^#RTI_Control#@([^@]+)@%%([^%%]+)%%%$([^%$]*)%$~([^~]*)~")
-
- -- send reply
- if value == 'HELLO' then
- sock:send('#RTI_Control#@HEARTBEAT@%SYSTEM%$STRING$~HELLO TO YOU~\r\n')
- end
- if command == 'BUTTON' then
- --Button pressed. Call for function
- pushbutton(address, value)
- end
- if command == 'WRITEADDRESS' then
- --Write received value into group address
- grp.write(address, value)
- end
- if command == 'READSTRING' then
- --String value request
- value = updatestring(address)
- if value ~= nil then
- udpsend("UPDATESTRING",address,"STRING",value)
- end
- end
- if command == 'READBUTTON' then
- --Button status request
- value = updatebutton(address)
- if value ~= nil then
- udpsend("UPDATEBUTTON",address,"BOOLEAN",value)
- end
- end
- if command == 'READADDRESS' then
- --Group address status request
- value = grp.getvalue(address)
- if value ~= nil then
- if type(value) == 'boolean' and datatype == 'BOOLEAN' then
- udpsend("UPDATEADDRESS",address,"BOOLEAN",(value and 1 or 0))
- elseif type(value) == 'integer' and datatype == 'INTEGER' then
- udpsend("UPDATEADDRESS",address,"INTEGER",value)
- end
- end
- 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 6789
- tcpserver = socket.bind('*', 6789)
-
- -- 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 12345
- udpserver = socket.udp()
- udpserver:setsockname('127.0.0.1', 12345)
- 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
- --alert(message)
- for id, sock in pairs(clients) do
- sock:send(message .. '\r\n')
- end
- end
-
- copas.step(0.1)
- end
The following commands can be received from RTI controller:
- “BUTTON” – controller informs that the button is pressed. In this example the function pushbutton(address, value) will be called. Button numbers (address) are stored in interval from 1 to 250. Value=1 – button is pressed; value=0 – button is released
- “WRITEADDRESS” – controller informs that the group address should be changed
- “READSTRING” – request fro string content. In this example string is returned by function updatestring(address)
- “READBUTTON” – request for button status. In this example button status is set from function updatebutton(address)
- “READADDRESS” – request for address status
Event program
Event-based script will be based on group address 1/0/1. In case of object ON (lamp), the telegram “ON” will be sent to all controllers which are currently connected to LogicMachine. In case of object OFF, the telegram “OFF” will be sent.
- address = event.dst
- value = knxdatatype.decode(event.datahex, dt.bool)
- sendaddress(address,'BOOLEAN',(value and 'ON' or 'OFF'))
The following event based program will track object 1/1/1. In case of temperature change in the room, the string with current temperature will be sent to all controllers which are currently connected to LogicMachine.
- address = event.dst
- local value = knxdatatype.decode(event.datahex, dt.float16)
- alert('address = %s, value = %s', address, value)
- local t = tostring(value)
- alert('t = %s', value)
- sendstring(address, string.format('%.1f', t))
Demo driver of RTI and further information
Demo driver can be downloaded here.
In case of interest to receive full version of driver, please contact the creator of this example Alexey Krasovkiy
e-mail: kao@itservice-vrn.ru
Please note that driver licence is mapped to a specific controller. The count of drivers on one controller is unlimited thus count of group addresses, strings and buttons are not limited. For additional functionality please contact the developer.