User Tools

Site Tools


diehl-inte

This is an old revision of the document!


DIEHL INTE heat meter

The meter has integrated Mbus port.

<code lua> – MAIN CODE STARTS AT LINE 118 function onScanStart ()

  now = os.time()

end

POLL_DELAY = 60 * 15 – poll rate constant in sec. HEX_NUMBERING = 16 – numbering system conversion

—— convenient print function ———– function tprint(t, indent)

  if not indent then indent = 0 end 
  for k, v in pairs(t) do 
      local formatting = string.rep(' ', indent) .. k .. ': '
      if type(v) == "table" then 
          ERROR(formatting) 
          tprint(v, indent + 1) -- recursive call 
      else
          if type(v) == "boolean" then 
              v = v and "TRUE" or "FALSE"
          end 
          ERROR(formatting .. v) 
      end 
  end 

end

– prints any parameters function DBG(…)

  for i = 1, #arg do 
      local curArgument = arg[i]
      if type(curArgument) == 'table' then 
          tprint(curArgument)
      else 
          INFO(tostring(curArgument))
      end 
  end 

end ; DEBUG = DBG

—— Table helpers —————————– function table.findPattern(t, pttrn)

for tabIndex, _ in ipairs(t) do

      local matchFlag = true 

for seqIndex, sequenceByte in ipairs(pttrn) do – checking pttrn inside a t

          matchFlag = matchFlag and (sequenceByte == t[tabIndex + seqIndex - 1])
          if (not matchFlag) then 
              matchFlag = false 
              break
          end 
      end
      if matchFlag then 
          return (tabIndex + #pttrn) 
      end 
  end 
  return false  

end

function table.sub(t, startIndex, endIndex)

  local tmpTable = {}
  for k = startIndex, endIndex do 
      table.insert(tmpTable, t[k])
  end  
  return tmpTable

end

function table.hexStr(hextab, spacer)

  local hex = {} 
  for _, hexbyte in ipairs(hextab) do 
      table.insert(hex, getHexByteAsStr(hexbyte))
  end 
  return table.concat(hex, spacer)

end – converts tab to bcd number table.bcd = function(t)

  local hex = table.hexStr(t)
  local out = tonumber(hex) ;  DBG('entered bdc with', t, 'hex view: ' .. hex, 'out: ' .. tostring(out)) 
  return out 

end – integer convertions table.int = function(t)

 return tonumber(table.hexStr(t), HEX_NUMBERING) 

end

table.float = function(t)

 return t 

end

– gets 2 - char hex string of a byte function getHexByteAsStr(inputByte)

  local strByte = string.format("%X", inputByte)    
  return (#strByte == 1 and '0' .. strByte) or strByte

end

table.reverse = function (tab)

  local outTable = {}
  for i = #tab, 1, -1 do 
      table.insert(outTable, tab[i])
  end 
  return outTable

end

– delimiters & control bytes SHORT_FRAME_STX = 0x10 SEND_NKE = 0x40 ACK = 0xE5 ETX = 0x16 CTRL_LONG_FRAME_STX = 0x68

REQ_UD2 = 0x7B – Request for Class 2 Data FCB REQ_UD2_ = 0x5B – Request for Class 2 Data Frame count bit

BROADCAST_ADDR = 0xFE – 254 CRC_ = 0x59

– prboe packet – PROBE_PACKET = {SHORT_FRAME_STX, REQ_UD2_, BROADCAST_ADDR, CRC_, ETX} – TxD:10 5B FE 59 16 PROBE_PACKET = {SHORT_FRAME_STX, REQ_UD2, BROADCAST_ADDR, CRC_, ETX} – TxD:10 5B FE 59 16

  1. - its indexes

REQ_UD2_POS = 2 PROBE_PCKT_ADDR_POS = 3 PROBE_PACKET_CRC_POS = 4 PROBE_PACKET_PAYLOAD_LEN = 2

data = {empty = {}}

dataHandlers = {

  1. - energy = {pattern = {0x4, 0x07}, length = 4, func = table.float},

energy = {pattern = {0x4, 0x07}, length = 4, func = table.float},

  
  volume = {pattern = {0x4, 0x15},       length = 4, func = table.int}, 
  power  = {pattern = {0x5, 0x2E},       length = 4, func = table.float}, 
  flow   = {pattern = {0x5, 0x3E},       length = 4, func = table.float},
  
  tint   = {pattern = {0x2, 0x59},       length = 2, func = table.int}, -- fwd.   temp. 
  text   = {pattern = {0x2, 0x5D},       length = 2, func = table.int}, -- return temp. 
  
  err   =  {pattern = {0x2, 0xFD, 0x17}, length = 2, func = table.int},
  
  upt   =  {pattern = {0x4, 0x20},       length = 4, func = table.int}  -- uptime , sec. 

}

function createDevices () – xtraFields are used for comments

 addDevice{name = "E",     shift = 0, base = 10, xtraFields = {'energy'}           } 
 addDevice{name = "V",     shift = 0, base = 10, xtraFields = {'volume'}           } 
 addDevice{name = "P",     shift = 0, base = 10, xtraFields = {'power'}            } 
 addDevice{name = "Q",     shift = 0, base = 10, xtraFields = {'flow'}             }   
 addDevice{name = "FWD",    shift = 0, base = 10, xtraFields = {'temp. internal'}   }   
 addDevice{name = "RET",    shift = 0, base = 10, xtraFields = {'temp. external'}   }   
 addDevice{name = "ERR",   shift = 0, base = 10, xtraFields = {'error flags'}  }   
 addDevice{name = "UPT",   shift = 0, base = 10, xtraFields = {'error flags'}  }   

end

function readRegister (reg, device, unitId)

  
  local function initMeter() 
      DBG("Etnered init packet for inte")
      local INTE_INIT_FRAME = {SHORT_FRAME_STX, 
                               SEND_NKE, 
                               BROADCAST_ADDR, 0x00 -- CRC #4 
                                               , ETX} 
      
      INTE_INIT_FRAME[3] = unitId
      INTE_INIT_FRAME[4] = getCRC(INTE_INIT_FRAME, 2, 2)
  
      if (not sendBytes(INTE_INIT_FRAME) ) then
          ERROR("Could not sent bytes!")
          return false
      end
      
      if (readOneByte() ~= ACK) then  
          ERROR("No ack after init packet!") ; return false
      else 
          DBG("Ack received for INIT_PACKETS")
      end 
      
      local CURRENT_PARAMS_SELECTION = { CTRL_LONG_FRAME_STX, 0x04, 0x04, CTRL_LONG_FRAME_STX
                                         , 0x53, BROADCAST_ADDR, 0x50, 0x0,  0x0 -- CRC #9 
                                         , ETX}
      CURRENT_PARAMS_SELECTION[6] = unitId
      CURRENT_PARAMS_SELECTION[9] = getCRC(CURRENT_PARAMS_SELECTION, 5, 4)
      
      if (not sendBytes(CURRENT_PARAMS_SELECTION) ) then
          ERROR("Could not send bytes for params selection!") ; return false
      end
      
      if (readOneByte() ~= ACK) then  
          ERROR("No ack after cur params selection packet!") ; return false
      else 
          DEBUG("Ack received for params selection") ; return true 
      end 
  end 
  if (not lastReadTimeStamp or (now - lastReadTimeStamp) >= POLL_DELAY ) then 
      DBG("Starting inte read by lastReadTimeStamp")
      
      if (not init and not initMeter() ) then 
          ERROR("Could not init INTE meter!")
          init = false ; return false 
      else 
          init = true  -- set global for init meter 
      end 
      
      PROBE_PACKET[PROBE_PCKT_ADDR_POS] = unitId
      PROBE_PACKET[PROBE_PACKET_CRC_POS] = getCRC(PROBE_PACKET
                                                  , REQ_UD2_POS
                                                  , PROBE_PACKET_PAYLOAD_LEN)

if (not sendBytes(PROBE_PACKET) ) then

          ERROR("Could not sent bytes for DATA_QUERY!") 
          return false
      end

local meterDataFrame = readUntil(ETX)

      
      if (meterDataFrame and (#meterDataFrame > 10) ) then
                                          DBG(table.hexStr(meterDataFrame, ' '))
          -- parsing 
          for param, struc in pairs(dataHandlers) do 
              DBG('trying to read ' .. tostring(param))
              local foundPos = table.findPattern(meterDataFrame, struc.pattern)
              
              if foundPos then
                  DBG('             found data at: '.. foundPos)
                  local foundBytes = table.sub(meterDataFrame
                                               , foundPos
                                               , foundPos + struc.length - 1) 
                  
                  foundBytes = table.reverse(foundBytes)      
                  local actualData = struc.func(foundBytes)   ; DBG("reversed actualData", '|', table.hexStr(foundBytes, ' '))
                  -- DBG('cur data structure: ', data)
                  data[param] = actualData

lastReadTimeStamp = now

              else 
                  ERROR("failed to find data for " .. param)
                  data[param] = false     
              end
          end 
      else 
          ERROR("failed to read long reply, meterDataFrame: " .. tostring(meterDataFrame))
          return false 
      end 
  end 
  DBG("going to return cached data: ", data )
  if data then 
      if (device.name == 'E')    then 
          DBG(device.xtraFields[1])
          return data.energy 
      end 
      if (device.name == 'V')    then return data.volume end 
      if (device.name == 'P')    then return data.power  end 
      if (device.name == 'Q')    then return data.flow   end 
      if (device.name == 'FWD')  then return data.tint   end 
      if (device.name == 'RET')  then return data.text   end 
      if (device.name == 'ERR')  then return data.err    end 
      if (device.name == 'UPT')  then return data.upt    end
  else 
      ERROR("the data is empty ... ")
      return false 
  end 
  

end

function writeRegister (reg, device, unitId, newValue) end

————————– Other helpers ————————–

function readUntil(endByte)

  local buf = {} 
  repeat 
      local b = readOneByte() 
      if b then 
          table.insert(buf, b)
      end 
  until (not b or (b == endByte))

return ((#buf >= 1) and buf) or false end

function getCRC(a, pos, len)

  local sum, mask  = 0, 0xFF

for i = pos, pos + len - 1 do

      sum = sum + a[i] 
      sum = bit.band(sum, mask)
  end 
  return sum

end

function readOneByte()

  local b = readBytes(1)
  return b and b[1] or false 

end

</lua>

diehl-inte.1697455159.txt.gz · Last modified: 2023/10/16 11:19 by emozolyak

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki