Управление освещением
Презентации
Технические решения на LogicMachine
Визуализация
  logicmachine.net.ru    Технические решения на LogicMachine    LogicMachine, как шлюз между контроллерами RTI и сетью KNX

LogicMachine, как шлюз между контроллерами RTI и сетью KNX

Задача:

Создать двухсторонний обмен данными между пультами RTI T2-Cs+ и устройствами в сети KNX.

Драйвер для контроллера XP-6:

Обмен данными с LogicMachine со стороны контроллера XP-6 осуществляется с помощью драйвера (LogicMachine.rtidriver). В настройках драйвера необходимо указать IP адрес LogicMachine и задать групповые адреса, состояние которых будет отображаться на пультах.

Скрипт для LogicMachine:

Функция должна быть добавлена в Скрипты -> Пользовательские библиотеки (Scripting -> User libraries).

function updatestring(number)
-- обновление строк
  if number == '1' then
    local value = grp.getvalue('3/0/1') --запрос температуры в помещении
    local t = tostring(value)
    return string.format('%.1f', t) --преобразуем в строку для отображения на панели.
  end
-- Номера строк лежат в диапазоне от 1 до 250
end
 
function updatebutton(number)
  return false
end
 
function pushbutton(number)
  -- обработка нажатия кнопки
  if number == '1' then
    local value = grp.getvalue('3/0/2')    
    if value < 37 then
      value = value + 0.1 -- Меняем температуру в помещении
    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 -- Меняем температуру в помещении
    end
    grp.write('3/0/4', value)
  end
-- Номера кнопок лежат в диапазоне от 1 до 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

Резидентный скрипт – реализация сервера:

Добавим следующий скрипт в Скрипты –> Резидентные  (Scripting -> Resident) со значением параметра Интервал запуска (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
      --Нажали кнопку. Вызываем функцию, обработки нажатий.
      pushbutton(address, value)
    end
    if command == 'WRITEADDRESS' then
      --Записываем полученное значение в групповой адрес.
      grp.write(address, value)
    end
    if command == 'READSTRING' then
      --Запрос значения строки.
      value = updatestring(address)
      if value ~= nil then
        udpsend("UPDATESTRING",address,"STRING",value)
      end
    end
    if command == 'READBUTTON' then
      --Запрос состояния кнопки.
      value = updatebutton(address)
      if value ~= nil then
        udpsend("UPDATEBUTTON",address,"BOOLEAN",value)
      end
    end
    if command == 'READADDRESS' then
      --Запрос состояния группового адреса.
      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

От RTI контроллера могут быть получены следующие команды:
• «BUTTON» — контроллер сообщает, что нажата кнопка. В данном примере будет вызвана функция pushbutton(address, value). Номера кнопок (address) лежат в диапазоне от 1 до 250. Значение value = 1 означает, что кнопку нажали, а value = 0 – отпустили.
• «WRITEADDRESS» — контроллер сообщает, что нужно изменить значение группового адреса.
• «READSTRING» — запрос содержания строки. В данном примере строка возвращается через функцию updatestring(address).
• «READBUTTON» — запрос состояния кнопки. В данном примере состояние кнопки определяется через функцию updatebutton(address).
• «READADDRESS» — запрос состояния адреса.

Программа обработки событий:

Скрипт, основанный на событии, будет отслеживать объект ’1/0/1′. В случае включения объекта (лампы) будет послано сообщение “ON” всем контроллерам, которые в данный момент подключены к LogicMachine. В случае же выключения объекта будет передано сообщение – “OFF”.

address = event.dst
value = event.getvalue()
sendaddress(address,'BOOLEAN',(value and 'ON' or 'OFF'))

Скрипт, основанный на событии, будет отслеживать объект ’1/1/1′. В случае изменения температуры в помещении будет послана строка, содержащая значение температуры всем контроллерам, которые в данный момент подключены к LogicMachine.

address = event.dst
local value = event.getvalue()
alert('address = %s, value = %s', address, value)
local t = tostring(value)
alert('t = %s', value)
sendstring(address, string.format('%.1f', t))

Демодрайвер Rti предоставлен Красовским Алексеем (скачать)
Для получения полной версии драйвера обращайтесь по:
e-mail:kao@itservice-vrn.ru
тел.: +7(920)211-78-90




Copyright
© Embedded Systems Rus
2019. All Rights Reserved