apator-apt-mbu-na-1c
Table of Contents
Apator APT-MBU-NA-1C water meter head
This head is used for turbine type water flowmeters which is put on the top of the water meter device. You can use custom protocol feature for reading this device.
Connection setup
Custom protocol source code
POLL_DELAY = 60 -- poll rate constant in sec. function DBG(...) ------ convenient print function ----------- for i = 1, #arg do local curArgument = arg[i] if type(curArgument) == 'table' then tprint(curArgument) else INFO(curArgument) end end end DEBUG = DBG HEX_NUMBERING = 16 -- numbering system conversion -- mbus control bytes BRDCAST_NET_LAYER_ADDR = 0xFD -- 253 BROADCAST_ADDR = 0xFE -- 254 -- delimiters SHORT_FRAME_STX = 0x10 SEND_NKE = 0x40 ACK = 0xE5 ETX = 0x16 CTRL_LONG_FRAME_STX = 0x68 REQ_UD2 = 0x7B -- Request for Class 2 Data REQ_UD2_ = 0x5B -- Request for Class 2 Data -- PROBE_PACKET = {SHORT_FRAME_STX, REQ_UD2_, 0xFE, 0x59, 0x16} original PROBE_PACKET = {SHORT_FRAME_STX, REQ_UD2_, BROADCAST_ADDR, 0x59, ETX} REQ_UD2_POS = 2 PROBE_PACKET_PAYLOAD_LEN = 2 PROBE_PACKET_CRC_POS = 4 -- 04 13 dif vif signature -- 1F 42 0F 00 vol. data example in INT32 VOL_DIF_VIF = {0x04, 0x13} VOL_DATA_LEN = 4 function onScanStart () now = os.time() end function createDevices () addDevice{name = "V", shift = 0, base = 10, xtraFields = {} } end function readRegister (reg, device, unitId) if (not lastReadTimeStamp or (now - lastReadTimeStamp) >= POLL_DELAY ) then 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 > 10) then local foundDataPos = tableFindPattern(meterDataFrame, VOL_DIF_VIF) if foundDataPos then lastReadTimeStamp = now local dataChunk = table.sub(meterDataFrame ,foundDataPos , foundDataPos + VOL_DATA_LEN - 1) local revDataHexStr = tabHexView(reverseTable(dataChunk) ) data = tonumber(revDataHexStr, HEX_NUMBERING) else ERROR("failed to find data !") data = false end else ERROR("failed to read reply!") data = false end end return data end function writeRegister (reg, device, unitId, newValue) end -------------------------- Helpers -------------------------- function tableFindPattern(inputTab, sequence) -- finds pattern in a table for tabIndex, _ in ipairs(inputTab) do local matchFlag = true for seqIndex, sequenceByte in ipairs(sequence) do -- checking sequence inside a inputTab matchFlag = matchFlag and (sequenceByte == inputTab[tabIndex + seqIndex - 1]) if (not matchFlag) then matchFlag = false break end end if matchFlag then return (tabIndex + #sequence) -- start of data end end return false end function table.sub(t, startIndex, endIndex) -- picks sub-table from a table local tmpTable = {} for k = startIndex, endIndex do table.insert(tmpTable, t[k]) end return tmpTable end function tabHexView(hextab, spacer) -- get string of a hex view for a table local hex = {} for _, hexbyte in ipairs(hextab) do table.insert(hex, getHexByteAsStr(hexbyte)) end return table.concat(hex, spacer) end function getHexByteAsStr(inputByte) -- gets 2 - char hex string of a byte local strByte = string.format("%X", inputByte) return (#strByte == 1 and '0' .. strByte) or strByte end function getCRC(a, pos, len) -- calc. CRC sum for the mbus packet 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 reverseTable(tab) -- reverses a table local outTable = {} for i = #tab, 1, -1 do table.insert(outTable, tab[i]) end return outTable end function readUntil(endByte) -- read input buffer untils endByte or timeout local ONE_BYTE = 1 local buf = {} repeat local rxSymbol = readBytes(ONE_BYTE)[ONE_BYTE] if rxSymbol then table.insert(buf, rxSymbol) end until (not rxSymbol or (rxSymbol == endByte)) return ((#buf >= ONE_BYTE) and buf) or false end
apator-apt-mbu-na-1c.txt ยท Last modified: 2023/05/17 08:40 by emozolyak