User Tools

Site Tools


scylar

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
scylar [2019/01/08 17:06] – created emozolyakscylar [2022/01/15 15:44] (current) – ↷ Links adapted because of a move operation 127.0.0.1
Line 1: Line 1:
-====== Connecting to Scylar heat meters ======+====== Connecting to Scylar INT 8 heat meters ======
  
-Пользовательский протокол для работы с счетчиком SCYLAR INT 8 по протоколу M-Bus+These heatmeters use Mbus protocol and can be added with the help of [[custom_protocols|custom protocols]]. 
 +Create custom protocol and copy the lua code below into the code block of that custom protocol.
  
-Протокол предназначен для чтения показаний из расходомера типа SCYLAR INT 8 с установленным модулем RS-485.  +If the meter has RS-485 board, it can be connected directly to WebHMI's RS-485 port. 
-Схема подключения счетчика к WebHMI:+
  
-{{ ::scylar_conn.png?direct&600 |}}+Wiring diagram:
  
 +{{ network:scylar_scheme_2.png?direct&700 |}}
  
 +Setup the connection for the meter as follows:
 +
 +{{ network:scylar_conn_setup_1.png?direct |}}
 +
 +The bus address  (96) can be found in the meters keypad screen #3, Paramter name 'Pri_Adr1'.
 +{{ network:primary_addr.png?direct&200 |}}
 +
 +{{ network:scylar_conn_setup_2.png?direct |}}
 +
 +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 |
 +
 +  The driver returns integer values. You should scale them appropriately to get exact values using Multiplier field 
 +  in register properties.
 +  
 +
 +== Driver test procedure ==
 +
 +Before testing the protocol in the field, it's preferrable to test it in a lab (if you have a meter on-hand). 
 +To simulate temperatures you can use resistors or potentiometers, note that return temperature have to be less than forward for 3 or more degrees (otherwise energy won't work). Flowmeter can be simulated by shorting 10-11 pins of i/o board. 
 +
 +{{ network:scylar_conn2.png?direct&300 |}}
 +
 +== Custom protocol (driver) code block ==
 +
 +<code lua>
 +-- 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
 +</code>
  
scylar.1546967174.txt.gz · Last modified: 2019/01/08 17:06 by emozolyak

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki