Copy // var msg = {
// "data" : "2D44B42570940310050E7202463904B42501070100002004138B0E17008410139B03000002FD17000002FD74BA16",
// "data2": "2D 44 B4 25 09 93 03 10 05 0E 72 21 53 51 04 B4 25 01 07 01 00 00 20 04 13 E0 2E 00 00 84 10 13 00 00 00 00 02 FD 17 00 00 02 FD 74 CB 16",
// }
var decodedMsg = msg;
if (msg && msg .data) {
decodedMsg = main ( msg .data)
}
if (msg && msg .ts) {
decodedMsg .ts = msg .ts
}
return {
msg : decodedMsg ,
metadata : metadata ,
msgType : msgType
};
// console.log(decodedMsg)
function main (data) {
var CI_FIELD = '78' ;
var ADDRESS_INDEX_START = 4 ;
var ADDRESS_INDEX_END = 7 ;
var VERSION_INDEX = 8 ;
var MEDIUM_FIELD = 'SystemComponent' ;
var MANUFACTURER_FIELD = 'IMT' ;
var VALUE_DIF_VIF = {
waterMeter : '04 13' ,
reverseWaterMeter : '84 10 13' ,
errorCodes : '02 fd 17' ,
batteryLifetime : '02 fd 74' ,
meterAddress : "72"
}
var STATUS_AND_EVENT_LIST_FIELD = [
// Don,t remove those following empty fields.
// Those are required since this full list is required for a 16-bit incoming status and event handling data
'' , '' , '' , '' , '' ,
'alarmOverFlow' ,
'alarmReverseFlow' ,
'alarmBatteryLow' ,
'alarmNoConsumption' ,
'' , '' , '' ,
'alarmLeak' ,
'alarmBurst' ,
'' ,
'alarmTamper'
]
var ERROR_LIST_FIELD = [
'overFlow' ,
'reverseFlow' ,
'batteryLow' ,
'noConsumption' ,
'leak' ,
'burst' ,
'tamper'
]
if ( ! String . prototype .includes) {
String . prototype . includes = function (search , start) {
'use strict' ;
if ( typeof start !== 'number' ) {
start = 0 ;
}
if (start + search . length > this . length ) {
return false ;
} else {
return this .indexOf (search , start) !== - 1 ;
}
};
}
function format (value) {
var bytes = value .replaceAll ( ' ' , '' ) .toLowerCase ();
var byteArr = []
for ( var i = 0 ; i < bytes . length ; i += 2 ) {
byteArr .push (bytes[i] + "" + bytes[i + 1 ])
}
return byteArr;
}
function isUnparsed (value) {
return value && !! value . length && value[ 0 ] === CI_FIELD ;
}
function getBodyPayloadStr (value) {
var payloadStartIndex = isUnparsed (value) ? 1 : 10 ;
if ( value . length > payloadStartIndex) {
return value .slice (payloadStartIndex) .join ( ' ' );
}
return '' ;
}
function getRevHexValue (value , startIndex , endIndex , convertToDecimal , devider) {
endIndex = endIndex || startIndex;
convertToDecimal = convertToDecimal || false ;
devider = devider || 1 ;
var result = Array.isArray(value) && !!value.length && value.slice(startIndex, endIndex + 1).reverse().join('') || null;
if ( !! result && convertToDecimal) {
result = parseInt (result , 16 ) / devider
}
return result;
}
function getAddressAndHeaders (value) {
var res = {};
if ( isUnparsed (value)) {
res .ciField = CI_FIELD ;
} else {
res = {
secondaryAddress : getRevHexValue (value , ADDRESS_INDEX_START , ADDRESS_INDEX_END ) ,
medium : MEDIUM_FIELD ,
length : getRevHexValue (value , 0 , 0 , true ) ,
manufacturer : MANUFACTURER_FIELD ,
version : getRevHexValue (value , VERSION_INDEX , VERSION_INDEX , true )
}
}
return res
}
function getDeviceValue (key) {
var result = 1 ;
if (key === 'waterMeter' || key === 'reverseWaterMeter' ) {
result = 1000 ;
} else if (key === 'flowTemperature' ) {
result = 10 ;
}
return result;
}
function getValuesByDifVif (valueStr , result) {
result = result || {};
if ( ! valueStr) {
return result;
}
var newValueStr;
var foundResKey;
for ( var key in VALUE_DIF_VIF ) {
if ( valueStr .startsWith ( VALUE_DIF_VIF [key])) {
foundResKey = key;
break ;
}
}
if ( !! foundResKey) {
var difVifArr = VALUE_DIF_VIF [foundResKey] .split ( ' ' );
if (foundResKey === 'reverseWaterMeter' || foundResKey === 'meterAddress' ) {
difVifArr[ 0 ] = '04'
}
var dataIndexLength = parseInt (difVifArr[ 0 ]);
var payloadLength = difVifArr . length + dataIndexLength;
result[foundResKey] = getRevHexValue (
valueStr .split ( ' ' ) ,
payloadLength-dataIndexLength, payloadLength-1, foundResKey !== 'errorCodes' && foundResKey !== 'meterAddress', getDeviceValue(foundResKey));
newValueStr = valueStr .split ( ' ' ) .slice (payloadLength) .join ( ' ' );
return getValuesByDifVif (newValueStr , result);
}
newValueStr = valueStr .split ( ' ' ) .slice ( 1 ) .join ( ' ' );
return getValuesByDifVif (newValueStr , result);
}
function getDeviceValues (value) {
var bodyPayloadStr = getBodyPayloadStr (value);
return getValuesByDifVif (bodyPayloadStr);
}
function getStatusAndEvents (errorCode) {
var errorCodeInt = parseInt (errorCode , 16 );
var errorCodeBin = errorCodeInt .toString ( 2 )
var shortLength = 16 - errorCodeBin . length ;
for ( var i = 0 ; i < shortLength; i ++ ) {
errorCodeBin = '0' + errorCodeBin;
}
var result = {
error : !! errorCodeInt ,
errors : ''
}
for ( var index = 0 ; index <= STATUS_AND_EVENT_LIST_FIELD . length ; index ++ ) {
var field = STATUS_AND_EVENT_LIST_FIELD [index];
if ( !! field) {
result[field] = index <= 3 ? parseInt (errorCodeBin[index]) : !! parseInt (errorCodeBin[index]);
var errorVal;
if ( !! result[field]) {
for ( var j = 0 ; j < ERROR_LIST_FIELD . length ; j ++ ) {
if ( field .toLowerCase () .includes ( ERROR_LIST_FIELD [j] .toLowerCase ())) {
errorVal = ERROR_LIST_FIELD [j];
result .errors += !! errorVal ? !! result .errors ? ', ' + errorVal : errorVal : '' ;
break ;
}
}
}
}
}
return result;
}
function decode (rowValue) {
var formattedValue = format (rowValue);
var addressAndHeaders = getAddressAndHeaders (formattedValue);
var deviceValues = getDeviceValues (formattedValue);
var statusAndEvents = getStatusAndEvents ( deviceValues .errorCodes)
return Object .assign ({} , addressAndHeaders , deviceValues , statusAndEvents);
}
return decode (data);
}