This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

CoolAutomation - CoolMasterNet integration
#1
CoolMasterNet device uses TCP instead of RS-232 for communication, so we've updated the script to work with IP.

1. Create a resident script with 0 sleep interval, change 192.168.3.20 to CoolMasterNet device IP. Status information is polled every 3 seconds.

2. Create objects:

All objects must have VRV tag set.

Set object names, using the following scheme (full address and function):
L1.101 on/off - 1-bit, unit on/off control
L1.101 setpoint - unit setpoint, 2-byte floating point
L1.101 mode - unit mode, 1-byte (0 = cool, 1 = heat, 2 = fan, 3 = dry, 4 = auto)
L1.101 fspeed - fan speed, 1-byte (0 = low, 1 = medium, 2 = high, 3 = top, 4 = auto)
L1 on/off - 1-bit, on/off control for all units on a given line
L* on/off - 1-bit, on/off control for all units on all lines

You can create status objects by adding "status" to object name, example:
L1.101 on/off status
L1.101 setpoint status
L1.101 mode status
L1.101 fspeed status
L1.101 temp status - room temperature, 2-byte floating point

Code:
if not client then
  require('socket')
  require('genohm-scada.eibdgm')

  IP = '192.168.3.20'
  PORT = 10102

  -- knx <> coolmaster mapping
  knxtocm = {}
  cmtoknx = {}

  function reverse(src)
    local res = {}

    for k, v in ipairs(src) do
      res[ v ] = k - 1
    end

    return res
  end

  -- integer<>text mode/fspeed value mapping
  modetotext = { 'cool', 'heat', 'fan', 'dry', 'auto' }
  texttomode = reverse(modetotext)
  speedtotext = { 'low', 'med', 'high', 'top', 'auto' }
  texttospeed = reverse(speedtotext)

  -- get all tagged objects and set mapping
  for _, object in ipairs(grp.tag('VRV')) do
    local address, fn, stat = unpack(object.name:split(' '))

    -- status object
    if stat then
      if not cmtoknx[ address ] then
        cmtoknx[ address ] = {}
      end

      cmtoknx[ address ][ fn ] = {
        id = object.id,
        value = grp.getvalue(object.id),
      }
    -- control object
    else
      knxtocm[ object.id ] = {
        address = address,
        fn = fn,
      }
    end
  end

  function checkerror(res, err)
    if not res then
      sock:close()
      sock = nil
      alert('CoolMaster error: %s', tostring(err))
    end

    return res, err
  end

  function connect()
    sock = socket.tcp()
    sock:settimeout(5)

    return checkerror(sock:connect(IP, PORT))
  end

  function send(data)
    if not sock then
      connect()
    end

    if sock then
      checkerror(sock:send(data))
    end
  end

  -- read single line from socket
  function readline()
    if not sock then
      connect()
    end

    if sock then
      return checkerror(sock:receive())
    end
  end

  function updateknx(address, fn, value, datatype)
    local object = cmtoknx[ address ] and cmtoknx[ address ][ fn ] or nil
    -- object not found
    if not object then
      return
    end

    -- no value or same value, no update required
    if value == nil or object.value == value then
      return
    end

    -- save new value and write to knx
    object.value = value
    grp.write(object.id, value, datatype)
  end

  function parseline(line)
    local address, status, setpoint, temp, speed, mode

    line = line:gsub('>', '')
    address = line:sub(1, 6)

    -- address is invalid, cannot parse line
    if address:sub(1, 1) ~= 'L' then
      return
    end

    -- on/off status
    status = line:sub(8, 9):lower() == 'on'
    updateknx(address, 'on/off', status, dt.bool)

    -- setpoint is integer
    setpoint = line:sub(12, 13)
    setpoint = tonumber(setpoint)
    updateknx(address, 'setpoint', setpoint, dt.float16)

    -- room temp is float, separated by comma
    temp = line:sub(16, 17)
    temp = tonumber(temp)
    updateknx(address, 'temp', temp, dt.float16)

    -- speed: low, med, high, auto
    speed = line:sub(20, 23):lower():trim()
    updateknx(address, 'fspeed', texttospeed[ speed ], dt.uint8)

    -- mode: cool, heat, fan, dry, auto
    mode = line:sub(25, 28):lower():trim()
    updateknx(address, 'mode', texttomode[ mode ], dt.uint8)
  end

  -- read current status
  function readstat()
    send('ls\r\n')

    -- read until error or end of stat
    while true do
      local line = readline()

      -- timeout or end occured
      if not line or line == 'OK' then
        break
      end

      parseline(line)
    end
  end

  -- handle group writes
  function eventhandler(event)
    local object, cmd, value, param

    object = knxtocm[ event.dstraw ]
    -- knx object not mapped, ignore
    if not object then
      return
    end

    -- on/off - boolean
    if object.fn == 'on/off' then
      value = knxdatatype.decode(event.datahex, dt.bool)
      cmd = value and 'on' or 'off'
    -- setpoint - floating point
    elseif object.fn == 'setpoint' then
      value = knxdatatype.decode(event.datahex, dt.float16)
      param = string.format('%.1f', value)
      cmd = 'temp'
    -- mode (fan, dry, auto)
    elseif object.fn == 'mode' then
      value = knxdatatype.decode(event.datahex, dt.uint8)
      cmd = modetotext[ value + 1 ]
    -- speed (low, medium, high, auto)
    elseif object.fn == 'fspeed' then
      value = knxdatatype.decode(event.datahex, dt.uint8)
      param = speedtotext[ value + 1 ]

      if param then
        cmd = 'fspeed'
      end
    end

    -- got valid command
    if cmd then
      -- append address to command
      cmd = cmd .. ' ' .. object.address

      -- append additional parameter if set
      if param then
        cmd = cmd .. ' ' .. param
      end

      send(cmd .. '\r\n')

      readline() -- command result
    end
  end

  -- knx connection
  client = eibdgm:new({ timeout = 1 })
  client:sethandler('groupwrite', eventhandler)

  -- start-up time
  sec, usec = os.microtime()
end

-- handle knx
client:step()

-- read stats every 3 seconds
diff = os.udifftime(sec, usec)
if diff < 0 or diff >= 3 then
  readstat()
  sec, usec = os.microtime()
end
Reply


Messages In This Thread
CoolAutomation - CoolMasterNet integration - by admin - 14.12.2015, 13:22

Forum Jump: