Теплосчетчики SKS-3 Axis Idustries
Материал из WebHMI Wiki
Версия от 18:30, 1 декабря 2016; Evgeniy.mozoliak (обсуждение | вклад)
Данные счетчики поддерживают протокол обмена M-Bus. В WebHMI работать с ними можно используя пользовательские протоколы. Текст протокола:
-- строка инициализации, сюда надо поставить адрес и контрольную сумму
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 -- getBCD
-- Расширенный поиск 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