scylar
This is an old revision of the document!
Connecting to Scylar INT 8 heat meters
These heatmeters use Mbus protocol and can be added with the help of custom protocols. Create custom protocol and copy the lua code below into the code block of that custom protocol.
If the meter has RS-485 board, it can be connected directly to WebHMI's RS-485 port.
Wiring diagram:
Setup the connection for the meter as follows:
The bus address (96) can be found in the meters keypad screen #3, Paramter name 'Pri_Adr1'.
This protocol can read the following heatmeter's data:
Parameter | Register address in project | Units |
---|---|---|
Energy | CE0 | 0.001 Gcal |
Energy tariff1 | CEA0 | 0.001 Gcal |
Energy tariff2 | CEB0 | 0.001 Gcal |
Volume | CV0 | 0.001 m3 |
Power | PWR0 | 0.001 kW |
Flow | CFL0 | 0.001 m3/h |
Forward temperature | FWT0 | 0.1 °C |
Return temperature | RET0 | 0.1 °C |
Operational days | OPD0 | days |
Error run hours | ERH0 | hours |
-- app reset template, modified then with addr and crc local app_reset = {0x68, 0x04, 0x04, 0x68, 0x53, 0x5D, 0x50, 0x50, 0x01, 0x16}; -- get data packet local REQ_UD2 = {0x10, 0x7B, 0x5D, 0xD8, 0x16}; local first_scan = true; local alreadyRead = false; local timeStmp = 0; local POLLTIME = 20; local err_cnt = 0; local dif_err_mask = 0x30; -- errorneous data read mask local resp3 = {}; -- response storage table AppRST = false; -- function createDevices () -- prefix dif dife vif vife len bytes addDevice({name = "FWT", shift = 0, base = 16, xtraFields = {0xA, 0x5A, 0, 0x2}}); -- forward temperature addDevice({name = "RET", shift = 0, base = 16, xtraFields = {0xA, 0x5E, 0, 0x2}}); -- rev. temp. -- addDevice({name = "ERH", shift = 0, base = 16, xtraFields = {0xA, 0xA6, 0x18, 0x2}}); -- error hours addDevice({name = "CFL", shift = 0, base = 16, xtraFields = {0xB, 0x3B, 0, 0x3}}); -- current flow rate addDevice({name = "CV", shift = 0, base = 16, xtraFields = {0xC, 0x13, 0, 0x4}}); -- current volume addDevice({name = "CE", shift = 0, base = 16, xtraFields = {0xC, 0xFB, 0x0D, 0x4}}); -- current volume addDevice({name = "CEA", shift = 0, base = 16, xtraFields = {0x8C, 0x10, 0xFB, 0x0D, 0x4}}); -- current energy T1 mask addDevice({name = "CEB", shift = 0, base = 16, xtraFields = {0x8C, 0x20, 0x13, 0x00, 0x4}}); -- current energy T1 mask addDevice({name = "PWR", shift = 0, base = 16, xtraFields = {0x0C, 0x2B, 0x00, 0x4}}); -- power -- addDevice({name = "OPD", shift = 0, base = 16, xtraFields = {0xA, 0x27, 0, 0x2}}); -- op. days end -- of createDevices function readRegister (reg, device, unitId) -- substitution with correct flag app_reset[6] = unitId; REQ_UD2[3] = unitId; -- and now CRC app_reset[9] = getCRC(app_reset,5,4); REQ_UD2[4] = getCRC(REQ_UD2,2,2); -- Application reset if not AppRST then -- was app reset made ? --------- App reset ----------- res = sendBytes(app_reset); -- send it TRACE("Request was sent!"); if (res == false) then TRACE("app reset could not send bytes"); return false; end local response = readBytes(1); -- read one byte if (response == false) then ERROR("Can't read response") ; return false; else TRACE("App reset was successfull"); AppRST = true; err_cnt = 0; end end local CRCvar, CRCinPacket = 0,0; -- reset flag and do app reset againg if err_cnt > 100 then AppRST = false; TRACE("Repeated AppRST after 100 errors"); return false; end -- err check -- after polltime ask againg local now = os.time(); if (not alreadyRead) then timeStmp = now; -- REQ_UD2 -- local resp2 = sendBytes(REQ_UD2); if (resp2 == false) then TRACE("Can't send bytes"); return false; end -- get first 4 bytes local response2 = readBytes(4); if (response2 == false) then ERROR("Can't read response, false returned") ; err_cnt = err_cnt + 1; return false; elseif not ((response2[1] == 0x68) and (response2[4] == 0x68)) then ERROR("Wrong response format!68 ~= 68 ") ; err_cnt = err_cnt + 1; return false; elseif (#response2 ~= 4 ) then ERROR("Wrong response2 len , length = "..tostring(#response2)) ; return false; else -- normal read local length = response2[2]; -- get length -- get everything resp3 = readBytes(length+2); if (resp3 == false) then ERROR("Can't read response, false returned ") ; err_cnt = err_cnt + 1; return false; elseif (#resp3 ~= (length+2)) then ERROR("Wrong resp3 len , length = "..tostring(#resp3)) ; return false; else -- glue packets for i,v in pairs(resp3) do table.insert(response2,v); end -- crc check CRCinPacket = tonumber(tostring(response2[#response2-1])); TRACE("CRCinPacket is "..CRCinPacket); CRCvar = getCRC(response2,5,length); TRACE("Calculated CRCvar is "..CRCvar); -- TRACE("And CRCvar "..string.format("%X",CRCvar)); if CRCinPacket == CRCvar then TRACE("They are equal"); else TRACE("They are NOT equal"); ERROR("Can't read response, false returned because of CRC !!! ") ; err_cnt = err_cnt + 1; return false; end -- debug print TRACE("C field = "..tostring(resp3[1])); TRACE("Addr field = "..tostring(resp3[2])); TRACE("CI field hex= "..string.format("%X",resp3[3])); -- ID 4 bytes -- local ID_str = ""; for i = 4, 7 do if resp3[i] < 10 then ID_str = "0"..string.format("%X",resp3[i])..ID_str; else ID_str = string.format("%X",resp3[i])..ID_str; end end TRACE("ID hex = "..ID_str); -- Manufacrutre 2 bytes -- local m_str = ""; for i = 8, 9 do if resp3[i] < 10 then m_str = "0"..string.format("%X",resp3[i])..m_str; else m_str = string.format("%X",resp3[i])..m_str; end end TRACE("Manufacture 2 bytes hex = "..m_str); -- Version -------------------- TRACE("Version = "..string.format("%X",resp3[10])); TRACE("Medium = "..string.format("%X",resp3[11])); TRACE("Access No. = "..string.format("%X",resp3[12])); TRACE("Status = "..string.format("%X",resp3[13])); ---------------------------------------- -- signature 2 bytes -- local m_str = ""; for i = 14, 15 do if resp3[i] < 10 then m_str = "0"..string.format("%X",resp3[i])..m_str; else m_str = string.format("%X",resp[i])..m_str; end end TRACE("Signature 2 bytes hex = "..m_str); alreadyRead = true; end end end -- if not alreadyRead -- set polling time if (now - timeStmp) >= POLLTIME then alreadyRead = false; end -- local position = 0; local resp_num = 0; local resp_tab = {}; local err_flag = false; local DataLength = 0; local FloatFlag = 0; TRACE("Parsing register "..device.name); position, DataLength, FloatFlag, err_flag = ExtFind(resp3,device.xtraFields); if (not err_flag) and (position ~= nil) then TRACE("parsed .. the following "); TRACE(reg.addr); TRACE("And device name = "..device.name); resp_tab, resp_num = getBCD(resp3, position, DataLength); return resp_num; else TRACE("Error while parsing.. "); return false; end end -- of function -- extra -- function getBCD(a, pos, len) -- reverse BCD table and make a number if (pos == nil) then TRACE("Pos = nil at entering to getBCD"); return 0xffff; end local str = ""; local result_table = {}; local bcd_sign = 1; local i, max_i = pos, pos+len-1; TRACE("getBCD pos is "..tostring(pos).." till "..tostring(max_i)); while i <= max_i do -- make string if (a[i] <= 0x0F) then str = "0"..string.format("%X",a[i])..str; else str = string.format("%X",a[i])..str; end -- make table table.insert(result_table,1,a[i]); i = i + 1; end -- check sign if string.find(str,"(F)") ~= nil then bcd_sign = -1; str = string.gsub(str,"F","0",1); end TRACE("getBCD Going to return .."..str.." and number is - "); local result = tonumber(str,10)*bcd_sign; TRACE(result); TRACE("table concat "..table.concat(result_table)); return result_table, result; end -- getBCD function getCRC(a,pos,len) local sum = 0; local mask = 0xFF; for i = pos, pos+len-1 do sum = sum + a[i]; sum = bit.band(sum,mask); end TRACE("CRC sum in the end of function = "..tostring(sum)); return sum; end -- getCRC function ExtFind(table, difvif_Table) TRACE("Entered ExtFind function "); local dib_len,vib_len = 1,1; local float_flag = false ; local data_LenTab = {[12] = 4, [10] = 2, [11] = 3}; local data_len = data_LenTab[bit.band(0x0F, difvif_Table[1])]; TRACE("data length is "..tostring(data_len)); if data_len == 0x05 then data_len = (data_len - 1) ; float_flag = true; TRACE("Float data found"); end local i = 1; while bit.band(0x80, difvif_Table[i]) == 0x80 do i = i + 1; end -- for dib_len = i; TRACE("DIB length = "..tostring(dib_len)); local j = i + 1; while bit.band(0x80, difvif_Table[j]) == 0x80 do j = j + 1; end -- for vib_len = j-i; TRACE("VIB length = "..tostring(vib_len)); for i,v in pairs(table) do local dif = 0; local err_flag = false; local dib_match = true; local vib_match = true; ------------------------------ -- TRACE("v in Dib search is"..string.format("%X",v)); if (bit.band(0x30, v) == 0x30) then -- TRACE("After bit.band v is with error mask "..string.format("%X",v)); err_flag = true ; dif = bit.band((0xFF - 0x30), v); else -- TRACE("No error , now v is "..string.format("%X",v)); dif = v; err_flag = false; end -- TRACE("dif found as "..string.format("%X",v)); local k=0; repeat k = k + 1; dib_match = dib_match and (table[i+k-1] == difvif_Table[k]); -- TRACE("table element ="..string.format("%X",table[i+k-1]).." difvif elmnt = ".. -- string.format("%X",difvif_Table[k])); -- TRACE("K ="..tostring(k).." dib_match = "..tostring(dib_match)); until (k==dib_len); -- TRACE("dib_match "..tostring(dib_match)); if dib_match then local g=0; repeat g = g + 1; vib_match = vib_match and (table[i+dib_len+g-1] == difvif_Table[dib_len+g]); -- TRACE("g = "..tostring(g).." Vib_match = "..tostring(vib_match)); until (g==vib_len); -- TRACE("vib_match "..tostring(vib_match)); end --if if dib_match and vib_match then TRACE("Going to return pos. len, float err flags "..tostring(i+dib_len+vib_len).." ".. tostring(data_len).." "..tostring(float_flag).." "..tostring(err_flag)); return i+dib_len+vib_len, data_len, float_flag, err_flag; end end -- for return nil; end -- of EXT Find -- function onScanStart () -- AppRST = false; end function writeRegister (reg, device, unitId, newValue) -- Add your code here end
scylar.1547030942.txt.gz · Last modified: 2019/01/09 10:49 by emozolyak