AMTRON SONIC D
Last updated
Last updated
// var msg = {
// // "data": "1E 04FB0E01000000 041301000000 022B0100 023E0102 025B0102 025F0102 0000 01020304 0102 01 01 01FD1701 ",
// // "data": "1F 04FB0E01020304 0000 01020304 0102 01 01 01FD1799"
// //"data": "21 04FB0E01020304 041301020304 0000 01020304 0102 01 01 01FD1799 046D01020304 440301020304"
// }
function format(value) {
data = value.replaceAll(' ', '');
return data;
}
var decodedMsg = msg;
var currentIndex = 0; // keeping track of current index is important
var data = format(msg.data)|| "";
if (msg && msg.data) {
decodedMsg = main();
}
return {
msg: decodedMsg,
metadata: metadata,
msgType: msgType
};
function main() {
// check message format
currentIndex = 2 ;
if( data[0]==='1' && data[1]==='E') return decodeStandard() ;
else if( data[0]==='1' && data[1]==='F') return decodeCompact() ;
else if( data[0]==='2' && data[1]==='0') return decodeJson() ;
else if( data[0]==='2' && data[1]==='1') return decodeScheduledDailyRedundant() ;
else if( data[0]==='2' && data[1]==='2') return decodeScheduledExtended() ;
else if( data[0]==='2' && data[1]==='3') return decodeCombinedHeatCooling() ;
else if( data[0]==='F' && data[1]==='A') return decodeClockMessage() ;
}
function decodeClockMessage() {
if(matchString(currentIndex, currentIndex+3 ,"046D")) {
return getDateTime();
}
return "Invalid date/time";
}
function decodeStandard(){
var energy = getEnergy();
var volume = getVolume();
var power = getPower();
var flow = getFlow();
var forwardTemperature = getForwardTemperature();
var returnTemperature = getReturnTemperature() ;
var meterAddress = getMeterAddress();
var errrorFlags = getErrorFlags() ;
var starndardMessage = {
energy: energy,
volume: volume,
power: power,
flow: flow,
forwardTemperature: forwardTemperature,
returnTemperature: returnTemperature,
meterAddress: meterAddress,
errrorFlags: errrorFlags
}
return starndardMessage;
}
function decodeCompact() {
var energy = getEnergy();
var meterAddress = getMeterAddress();
var errrorFlags = getErrorFlags() ;
var compactMessage = {
energy: energy,
meterAddress: meterAddress,
errrorFlags: errrorFlags
}
return compactMessage ;
}
function decodeScheduledDailyRedundant() {
var energy = getEnergy();
var volume = getVolume();
var meterAddress = getMeterAddress();
var errrorFlags = getErrorFlags() ;
var meterDateTime = getDateTime() ;
var accumulateEnergyAt24 = getAccumulatedEnergyAt_24() ;
var scheduledDailyRedundantMessage = {
energy: energy,
volume: volume,
meterAddress: meterAddress,
errrorFlags: errrorFlags,
meterDateTime: meterDateTime,
accumulateEnergyAt24: accumulateEnergyAt24
}
return scheduledDailyRedundantMessage;
}
function decodeCombinedHeatCooling() {
var heatEnergy = getEnergy();
var coolingEnergy = getCoolingEnergy(); // need to write
var volume = getVolume();
var forwardTemperature = getForwardTemperature();
var returnTemperature = getReturnTemperature();
var meterAddress = getMeterAddress();
var errrorFlags = getErrorFlags() ;
var combinedHeatCoolingMessage = {
energy: heatEnergy,
coolingEnergy: coolingEnergy,
volume: volume,
forwardTemperature: forwardTemperature,
returnTemperature: returnTemperature,
meterAddress: meterAddress,
errrorFlags: errrorFlags
}
return combinedHeatCoolingMessage;
}
function getPowerFlowFwTempRtTemp() {
// byte 0-2 difvif code
currentIndex += 6;
// byte 3 scaling of power
currentIndex += 1;
// byte 4-5 forward temperature
var forwardTemperature = parseInt(getReversedValue( currentIndex, currentIndex+3), 16)+ "°C"; currentIndex += 4;
// byte 6-7 return temperature
var returnTemperature = parseInt(getReversedValue(currentIndex, currentIndex+3 ), 16)+"°C"; currentIndex+= 4;
// byte 8-9 flow
var flow = parseInt(getReversedValue(currentIndex, currentIndex+3), 16)+ "m3/h"; currentIndex += 4;
// byte 10-11 power
var power = parseInt(getReversedValue(currentIndex, currentIndex+3 ), 16)+ "m3/h"; currentIndex += 4;
var ret = {
forwardTemperature: forwardTemperature,
returnTemperature: returnTemperature,
flow: flow,
power: power
}
return ret;
}
function getMeterIdErrorFlags() {
// byte 0-3 difvif codes 0x0DFF21E9
currentIndex += 8;
// byte 4 error flags
var errorFlags = parseInt(getReversedValue(currentIndex, currentIndex+1), 16 ) ;
currentIndex += 2 ;
// byte 5-8 meter id
var meterId = parseInt(getReversedValue(currentIndex, currentIndex+ 7), 16);
currentIndex += 8;
// byte 9-10 meter menufacturer
var meterManufacturer = parseInt(getReversedValue(currentIndex, currentIndex+3), 16);
currentIndex += 4;
// byte 11 meter version
var meterVersion = parseInt(getReversedValue(currentIndex, currentIndex+1), 16);
currentIndex += 1;
// byte 11 meter version
var deviceType = parseInt(getReversedValue(currentIndex, currentIndex+1), 16);
currentIndex += 1;
var ret = {
errorFlags: errorFlags,
meterId: meterId,
meterManufacturer: meterManufacturer,
meterVersion: meterVersion,
deviceType: deviceType
}
return ret;
}
function decodeScheduledExtended() {
var energy = getEnergy();
var volume = getVolume();
var powerFlowFwTempRtTemp = getPowerFlowFwTempRtTemp() ;
var meterIdErrorFlags = getMeterIdErrorFlags();
var meterDateTime = getDateTime() ;
var scheduledExtendedMessage = {
energy: energy,
volume: volume,
forwardTemperature: powerFlowFwTempRtTemp.forwardTemperature,
returnTemperature: powerFlowFwTempRtTemp.returnTemperature,
flow: powerFlowFwTempRtTemp.flow,
power: powerFlowFwTempRtTemp.power,
errorFlags: meterIdErrorFlags.errorFlags,
meterId: meterIdErrorFlags.meterId,
meterManufacturer: meterIdErrorFlags.meterManufacturer,
meterVersion: meterIdErrorFlags.meterVersion,
deviceType: meterIdErrorFlags.deviceType,
meterDateTime: meterDateTime
}
return scheduledExtendedMessage;
}
function decodeJson() {
return data;
}
function getDateTime() {
currentIndex += 4;
var dateTimeString = "" ;
var currentBit= 0 ;
for(var i=currentIndex; i<currentIndex+8 ; i++ ) dateTimeString += data[i] ;
// dateTimeString = (parseInt(dateTimeString, 16).toString(2)).padStart(8, '0') ;
dateTimeString = convertHexToBinary(dateTimeString );
// bit 31-28 total 4 bit
var yearHigh = dateTimeString.substring(currentBit, currentBit+3 ) ; currentBit+= 4 ;
// bit 27-24 total 4 bit
var month = dateTimeString.substring(currentBit, currentBit+3 ) ; currentBit+= 4 ;
// bit 23-21 total 3 bit
var yearLow = dateTimeString.substring(currentBit, currentBit+2 ) ; currentBit+= 3 ;
// bit 20-16 total 5 bit
var day = dateTimeString.substring(currentBit, currentBit+4 ) ; currentBit+= 5 ;
// bit 15 total 15 bit
var summertimeFlag = dateTimeString.substring(currentBit, currentBit ) ; currentBit+= 1 ;
// bit 12-8 total 5 bit
var hour = dateTimeString.substring(currentBit, currentBit+4 ) ; currentBit+= 5 ;
// bit 7 error flag total 1 bit
var errorFlag = dateTimeString.substring(currentBit, currentBit ) ; currentBit+= 1 ;
// bit 6 total 1
var reservedFutureUse = dateTimeString.substring(currentBit, currentBit ) ; currentBit+= 1 ;
// bit 0-5 minute total 6
var minute = dateTimeString.substring(currentBit, currentBit+5 ) ; currentBit+= 6 ;
currentIndex += 8;
var YY = parseInt(yearHigh+"" + yearLow, 2 ) ;
var MM = parseInt(month, 2) ;
var DD = parseInt(day, 2) ;
var HH = parseInt(hour, 2);
var MM_Minute= parseInt(minute, 2);
var dateTime = YY +"-"+ MM +"-"+DD +" "+ HH+ ":" + MM_Minute ;
return dateTime;
}
function matchString(startIndex, endIndex , str) {
for( var i=startIndex, j= 0; i<= endIndex; i++ ,j++) if(data[i]!== str[j] ) return false;
return true;
}
function getReversedValue(startIndex, endIndex) {
var str ="" ;
for(var i=endIndex-1 ; i>= startIndex ;i-=2 ) str += data[i] +""+ data[i+1] ;
return str ;
}
function getErrorFlags( ) {
var errorFlags= parseInt( getReversedValue( currentIndex+6, currentIndex+7), 16);
currentIndex += 8;
return errorFlags ;
}
function getEnergy() {
// start from 2nd bit
var difVif = ["0403", "0404", "0405", "0406", "0407", "040E", "040F", "04FB0D", "04FB0E", "04FB0F"] ;
var multiplier = [1, 10, 100,1, 10, 1, 10,1, 10, 100] ;
var unit = ["Wh" , "Wh", "Wh", "kWh", "kWh", "MJ", "MJ", "MCal","MCal","MCal" ];
var energy;
for(var i=0;i< difVif.length ;i++ ) {
if(matchString(currentIndex, currentIndex+ difVif[i].length - 1, difVif[i])) {
var start = currentIndex+difVif[i].length ;
var end = currentIndex + (i<=6?11: 13 );
energy = ( parseInt( getReversedValue(start, end ), 16 ) * multiplier[i]) + unit[i] ;
currentIndex = currentIndex + (i<=6 ? 12: 14 ) ;
return energy ;
}
}
}
function getCoolingEnergy() {
// start from 2nd bit
var difVif = ["0483FF02", "0484FF02", "0485FF02", "0486FF02", "0487FF02", "048EFF02", "048FFF02", "04FB8DFF02", "04FB8EFF02", "04FB8FFF02"] ;
var multiplier = [1, 10, 100,1, 10, 1, 10,1, 10, 100] ;
var unit = ["Wh" , "Wh", "Wh", "kWh", "kWh", "MJ", "MJ", "MCal","MCal","MCal" ];
// energy 6-7 byte
var energy;
for(var i=0;i< difVif.length ;i++ ) {
if(matchString(currentIndex, currentIndex+ difVif[i].length - 1, difVif[i])) {
var start = currentIndex+difVif[i].length ;
var end = currentIndex + (i<=6?14: 16 );
energy = ( parseInt( getReversedValue(start, end ), 16 ) * multiplier[i]) + unit[i] ;
currentIndex = currentIndex + (i<=6 ? 15: 17 ) ;
return energy ;
}
}
}
function getAccumulatedEnergyAt_24() {
var difVif = ["4403", "4404", "4405", "4406", "4407", "440E", "440F", "44FB0D", "44FB0E", "44FB0F"] ;
var multiplier = [1, 10, 100,1, 10, 1, 10,1, 10, 100] ;
var unit = ["Wh" , "Wh", "Wh", "kWh", "kWh", "MJ", "MJ", "MCal","MCal","MCal" ];
// energy 6-7 byte
var energy;
for(var i=0;i< difVif.length ;i++ ) {
if(matchString(currentIndex, currentIndex+ difVif[i].length - 1, difVif[i])) {
var start = currentIndex+difVif[i].length ;
var end = currentIndex + (i<=6?11: 13 );
energy = ( parseInt( getReversedValue(start, end ), 16 ) * multiplier[i]) + unit[i] ;
currentIndex = currentIndex + (i<=6 ? 12: 14 ) ;
return energy ;
}
}
}
function getVolume() {
var difVif = ["0413", "0414", "0415", "0416", "0417"] ;
var multiplier = [0.001, 0.01, 0.1, 1, 10] ;
var unit = ["m3", "m3", "m3", "m3", "m3"];
// volume 6 0413 xxxx xxxx
var volume;
for(var i=0;i< difVif.length ;i++ ) {
if(matchString(currentIndex, currentIndex+ difVif[i].length - 1, difVif[i])) {
var start = currentIndex+difVif[i].length ;
var end = currentIndex + 11;
volume = ( parseInt( getReversedValue(start, end ),16 ) * multiplier[i]) + unit[i] ;
currentIndex = currentIndex + 12 ;
return volume ;
}
}
}
function getPower() {
var difVif = ["022B", "022C", "022D", "022E", "022F"] ;
var multiplier = [1, 10, 100, 1, 10] ;
var unit = ["W", "W", "W", "kW", "kW"];
// volume 6 0413 xxxx xxxx
var power;
for(var i=0;i< difVif.length ;i++ ) {
if(matchString(currentIndex, currentIndex+ difVif[i].length - 1, difVif[i])) {
var start = currentIndex+difVif[i].length ;
var end = currentIndex + 7;
power = ( parseInt( getReversedValue(start, end ), 16 ) * multiplier[i]) + unit[i] ;
currentIndex = currentIndex + 8 ;
return power ;
}
}
}
function getFlow() {
var difVif = ["023B", "023C", "023D", "023E", "023F"] ;
var multiplier = [0.001, 0.01, 0.1, 1, 10] ;
var unit = ["m3/h", "m3/h", "m3/h", "m3/h", "m3/h"];
// volume 6 0413 xxxx xxxx
var flow;
for(var i=0;i< difVif.length ;i++ ) {
if(matchString(currentIndex, currentIndex+ difVif[i].length - 1, difVif[i])) {
var start = currentIndex+difVif[i].length ;
var end = currentIndex + 7;
flow = ( parseInt( getReversedValue(start, end ) , 16) * multiplier[i]) + unit[i] ;
currentIndex = currentIndex + 8 ;
return flow ;
}
}
}
function getReturnTemperature() {
var difVif = ["025C", "025D", "025E", "025F"] ;
var multiplier = [0.001, 0.01, 0.1, 1] ;
var unit = ["°C", "°C", "°C", "°C"];
// volume 6 0413 xxxx xxxx
var returnTemperature;
for(var i=0;i< difVif.length ;i++ ) {
if(matchString(currentIndex, currentIndex+ difVif[i].length - 1, difVif[i])) {
var start = currentIndex+difVif[i].length ;
var end = currentIndex + 7;
returnTemperature = ( parseInt( getReversedValue(start, end ), 16) * multiplier[i]) + unit[i] ;
currentIndex = currentIndex + 8 ;
return returnTemperature ;
}
}
}
function getForwardTemperature() {
var difVif = ["0258", "0259", "025A", "025B"] ;
var multiplier = [0.001, 0.01, 0.1, 1] ;
var unit = ["°C", "°C", "°C", "°C"];
// volume 6 0413 xxxx xxxx
var forwardTemperature;
for(var i=0;i< difVif.length ;i++ ) {
if(matchString(currentIndex, currentIndex+ difVif[i].length - 1, difVif[i])) {
var start = currentIndex+difVif[i].length ;
var end = currentIndex + 7;
forwardTemperature = ( parseInt( getReversedValue(start, end ), 16 ) * multiplier[i]) + unit[i] ;
currentIndex = currentIndex + 8 ;
return forwardTemperature ;
}
}
}
function getMeterAddress() {
// 0-1 byte dif/vif code
currentIndex+= 4 ;
// 2-5 byte is meter address
var meterId = parseInt(getReversedValue(currentIndex , currentIndex+ 7), 16);
currentIndex += 8 ;
// 6-7 byte meter manufacturer
var meterManufacturer = parseInt(getReversedValue(currentIndex, currentIndex+ 3), 16);
currentIndex += 4 ;
// byte 8 meter version
var meterVersion = parseInt(getReversedValue(currentIndex, currentIndex+1 ), 16) ;
currentIndex += 2 ;
// byte 9 device type
var deviceType = parseInt(getReversedValue(currentIndex, currentIndex+1), 16 ) ;
currentIndex += 2 ;
var meterAddress = {
meterId: meterId,
meterManufacturer: meterManufacturer,
meterVersion: meterVersion,
deviceType: deviceType,
}
return meterAddress;
}
function convertHexToBinary(data ) {
var len = data.length * 4 ;
data = (parseInt(data, 16).toString(2)).padStart(8, '0') ;
while(data.length< len ) data = "0"+ data ;
return data ;
}