heat_meter_sks-3_axis_industries
This is an old revision of the document!
Heat meters SKS-3 by Axis Industries
These meters support the M-Bus exchange protocol. In WebHMI, you can work with them using custom protocols. This protocol can be used with appropriate adjustments for other M-Bus devices as well.
The text of the protocol:
-- строка инициализации, сюда надо поставить адрес и контрольную сумму local app_reset = {0x68, 0x04, 0x04, 0x68, 0x53, 0x5D, 0x50, 0x00, 0x01, 0x16}; -- запрос на получение данных local REQ_UD2 = {0x10, 0x7B, 0x5D, 0xD8, 0x16}; local err_cnt = 0; -- счетчик ошибок local dif_err_mask = 0x30; -- маска ошибки значения параметра local resp3 = {}; -- Таблица для хранения значимой части ответа local alreadyRead = false; -- флаг выполнения полного чтения local timeStmp = 0; -- метка времени между полными чтениями AppRST = false; -- инициализация прибора -- Вспомогатеьные функции -- function getBCD(a,pos,len) -- переворачивает в обратном порядке табличку BCD и делает число local str = ""; local i,max_i = pos, pos+len-1; TRACE("getDCD pos is "..tostring(pos).." till "..tostring(max_i)); while i <= max_i do if (a[i] < 0x0f) then str = "0"..string.format("%X",a[i])..str; else str = string.format("%X",a[i])..str; end i = i + 1; end TRACE("getDCD Going to return .."..str.." and number is - "); local result = tonumber(str,16); TRACE(result); return result; end -- getBCD -- GetCRC посчитать контрольную сумму function getCRC(a,pos,len) local sum = 0; for i = pos, pos+len-1 do sum = sum + a[i]; end TRACE("CRC sum = "..tostring(sum)); return sum; end -- getCRC -- Расширенный поиск 2-ая версия function efindpos(a, dif, dife, vif, vife) -- local dife_exists = false; local vife_exists = false; local err_flag = false; -- если есть ошибка в dif -- проверить наличие ошибок if (bit.band(0x30, dif) == 0x30) then err_flag = true ; end -- проверить dif if (bit.band(0x80, dif) == 0x80) then dife_exists = true ; end -- есть ли vife if (bit.band(0x80, vif) == 0x80) then vife_exists = true ; end -- if (not dife_exists) then if (not vife_exists) then -- dif vif for i,v in ipairs (a) do if dif == bit.band(v,0x0f) then -- сравниваем мл тетраду без ошибки if a[i+1] == vif then return i+2,err_flag; end end end -- loop else -- vife_exists for i,v in ipairs (a) do if dif == bit.band(v,0x0f) then -- сравниваем мл тетраду без ошибки if (a[i+1]==vif) and (a[i+2]==vife) then return i+3,err_flag; end end end -- loop end else -- dife_exists -- INFO("efindpos dife exists"..string.format("%X",dife)); if (not vife_exists) then -- dif vif for i,v in ipairs (a) do if (dif == bit.band(v,0x8f) and a[i+1] == dife ) then -- сравниваем мл тетраду без ошибки if a[i+2] == vif then return i+3,err_flag; end end end -- loop else -- dife vife_exists -- DEBUG("efindpos Vife exists"..string.format("%X",vife)); for i,v in ipairs (a) do local condition = ( (dif == bit.band(v,0x8f)) and (dife == a[i+1])); if condition then -- сравниваем мл тетраду без ошибки if (a[i+2]==vif) and (a[i+3]==vife) then return i+4,err_flag; end end end -- loop end end -- if return nil; -- ничего не нашли end -- of efindpos -- function createDevices () -- prefix dif dife vif vife len bytes addDevice({name = "VOL", shift = 0, base = 16, xtraFields = {0x4, 0, 0x14, 0, 0x4}}); -- current volume addDevice({name = "VOLB", shift = 0, base = 16, xtraFields = {0x84, 0x40, 0x14, 0, 0x4}}); -- current volume 2 addDevice({name = "HPWR", shift = 0, base = 16, xtraFields = {0x05, 0x00, 0x2E, 0, 0x4}}); -- тепл мощность 1 addDevice({name = "PWRB", shift = 0, base = 16, xtraFields = {0x85, 0x40, 0x2E, 0, 0x4}}); -- тепл мощность 2 addDevice({name = "TA", shift = 0, base = 16, xtraFields = {0x02, 0x00, 0x59, 0, 0x2}}); -- температура 1 addDevice({name = "TB", shift = 0, base = 16, xtraFields = {0x02, 0x00, 0x5D, 0, 0x2}}); -- температура 2 addDevice({name = "TC", shift = 0, base = 16, xtraFields = {0x02, 0x00, 0x65, 0, 0x2}}); -- температура 3 addDevice({name = "TCC", shift = 0, base = 16, xtraFields = {0x82, 0x40, 0x59, 0, 0x2}}); -- температура 3 addDevice({name = "TD", shift = 0, base = 16, xtraFields = {0x82, 0x40, 0x5D, 0, 0x2}}); -- температура 4 addDevice({name = "ENA", shift = 0, base = 16, xtraFields = {0x04, 0x00, 0x06, 0, 0x4}}); -- тепл мощность addDevice({name = "ENC", shift = 0, base = 16, xtraFields = {0x04, 0x00, 0x07, 0, 0x4}}); -- тепл мощность addDevice({name = "END", shift = 0, base = 16, xtraFields = {0x84, 0x40, 0x05, 0, 0x4}}); -- тепл мощность addDevice({name = "EAA", shift = 0, base = 16, xtraFields = {0x04, 0x00, 0x05, 0, 0x4}}); -- тепл мощность addDevice({name = "Q", shift = 0, base = 16, xtraFields = {0x05, 0x00, 0x3E, 0, 0x4}}); -- расход addDevice({name = "QB", shift = 0, base = 16, xtraFields = {0x85, 0x40, 0x3E, 0, 0x4}}); -- расход 2 end -- of createDevices function onScanStart () AppRST = false; end function readRegister (reg, device, unitId) -- подставить адреса в пакеты из адреса app_reset[6] = unitId; REQ_UD2[3] = unitId; -- теперь поставить контрольные СУММЫ app_reset[9] = getCRC(app_reset,5,4); REQ_UD2[4] = getCRC(REQ_UD2,2,2); -- Application reset if not AppRST then -- была ли инициализация ? local res = sendBytes(app_reset); -- отправка запроса на инициализацию DEBUG("Request was sent!"); if (res == false) then DEBUG("app reset was sent send bytes"); return false; end local response = readBytes(1); -- прием ответа if (response == false) then ERROR("Can't read response") ; return false; else DEBUG("App reset was successfull"); AppRST = true; err_cnt = 0; end end -- сделать инициализацию if err_cnt > 10 then AppRST = false; TRACE("Repeated AppRST after 10 errors"); return false; end -- err check -- если прошло 20 сек. тогда отправить полный запрос local now = os.time(); if (not alreadyRead) then timeStmp = now; -- запомнить время -- REQ_UD2 -- local resp2 = sendBytes(REQ_UD2); -- отправка запроса if (resp2 == false) then DEBUG("Can't send bytes"); return false; end -- прием первых 4 байт с ответом local response2 = readBytes(4); if (response2 == false) then ERROR("Can't read response") ; err_cnt = err_cnt + 1; return false; elseif not ((response2[1] == 0x68) and (response2[4] == 0x68)) then ERROR("Wrong response format!") ; err_cnt = err_cnt + 1; return false; else -- нормальное чтение читаем весь пакет local length = response2[2]; -- длину берем из пакета -- прием ВСЕГО ответа resp3 = readBytes(length+2); if (resp3 == false) then ERROR("Can't read response") ; err_cnt = err_cnt + 1; return false; else -- Отладочная печать DEBUG("C field = "..tostring(resp3[1])); DEBUG("Addr field = "..tostring(resp3[2])); DEBUG("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 DEBUG("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 DEBUG("Manufacture 2 bytes hex = "..m_str); -- Version -------------------- DEBUG("Version = "..string.format("%X",resp3[10])); DEBUG("Medium = "..string.format("%X",resp3[11])); DEBUG("Access No. = "..string.format("%X",resp3[12])); DEBUG("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",resp3[i])..m_str; end end DEBUG("Signature 2 bytes hex = "..m_str); alreadyRead = true; end end end -- настройка частоты опроса if (now - timeStmp) >= 15 then alreadyRead = false; end -- local position = 0; local resp_num = 0; local err_flag = false; -- Ищем и проверяем значение position, err_flag = efindpos(resp3, device.xtraFields[1], device.xtraFields[2], device.xtraFields[3], device.xtraFields[4]) ; -- преобразуем в число resp_num = getBCD(resp3, position, device.xtraFields[5]); err_cnt = 0; if not err_flag then return resp_num; else return 0xffff; end end -- of function function writeRegister (reg, device, unitId, newValue) -- Add your code here end
heat_meter_sks-3_axis_industries.1533213782.txt.gz · Last modified: 2018/08/02 12:43 by emozolyak