Hi , we get some UplinkCodec Error on the code we got from manufacturer and I get no response back on further help. And my lack of skills in javascript makes it almost impossible. There is a comment about the code is not compatible with Otto JS ES5.
Are there someone that can identify the problem in the decoder?
/Torbjorn
function Decode(payload, fPort) {
// Use the port to determine uplink data type
// All are MSB, Most Significant Bit/Byte first.
// Port 1: Protocol data
var obj = {};
var bytes = HexToBytes(payload);
function toHexString(byteArray) {
return Array.prototype.map
.call(byteArray, function (byte) {
return ("0" + (byte & 0xff).toString(16)).slice(-2);
})
.join("-");
}
if (fPort === 1) {
// Data
if (bytes[0] === 0x01) {
// Data received, byte 1 contains index
switch (bytes[1]) {
// FW Build hash
case 0x03: {
// Convert received butes to a string from byte 2 onwards
obj.fwVersion = String.fromCharCode.apply(String, bytes.slice(2));
break;
}
// CPU Voltage
case 0x06: {
// CPU Voltage is send as a 16-bit unsigned integer
obj.vdd = (bytes[2] << 8) | bytes[3];
break;
}
// CPU Temperature
case 0x0a: {
// CPU Temperature is send as a 16-bit unsigned int
// with 0.01C coding and 50C offset
obj.CPUTemperature = (((bytes[2] << 8) | bytes[3]) - 5000) / 100;
break;
}
// Status
case 0x20: {
// Bitfield, convert to string of base 2
obj.status = bytes[2].toString(2);
break;
}
// ReportInterval
case 0x22: {
// Interval encoded as uint16
obj.reportInterval = (bytes[2] << 8) | bytes[3];
break;
}
// MsgType
case 0x23: {
obj.msgType = bytes[2];
break;
}
default: {
}
}
} else if (bytes[0] === 0x02) {
// NACK received, byte 1 contains nack index
obj.nackIndex = bytes[1];
}
} else if (fPort === 2) {
function zfill(num, len) {
return (Array(len).join("0") + num).slice(-len);
}
function arrToUint16(byteArr, startIdx) {
return (byteArr[startIdx] << 8) | byteArr[startIdx + 1];
}
function arrToUint32(byteArr, startIdx) {
return (
(byteArr[startIdx] << 24) |
(byteArr[startIdx + 1] << 16) |
(byteArr[startIdx + 2] << 8) |
byteArr[startIdx + 3]
);
}
/*
function arrToUint40(byteArr, startIdx) {
// This doesn't work with old "otto" JS engine in "Go" language, 32-bit limits hit... Leave it for now
return (
(byteArr[startIdx] << 32) |
(byteArr[startIdx + 1] << 24) |
(byteArr[startIdx + 2] << 16) |
(byteArr[startIdx + 3] << 8) |
byteArr[startIdx + 4]
);
}
*/
// CoPilot change before know Otto JS engine
function arrToUint40(byteArr, startIdx) {
return (
(BigInt(byteArr[startIdx]) << BigInt(32)) |
(BigInt(byteArr[startIdx + 1]) << BigInt(24)) |
(BigInt(byteArr[startIdx + 2]) << BigInt(16)) |
(BigInt(byteArr[startIdx + 3]) << BigInt(8)) |
BigInt(byteArr[startIdx + 4])
);
}
function decodePower(pwrData) {
if ((1 << 15) & pwrData) {
// If bit 15 is set, scale by 100W
return (pwrData & ~(1 << 15)) * 100;
} else {
return pwrData;
}
}
function decodeVoltages(byteArr, startIdx) {
var lineVoltArr = arrToUint32(byteArr, startIdx);
var l1Volt_mV = ((lineVoltArr & 0x3ff00000) >> 20) * 250;
var l2Volt_mV = ((lineVoltArr & 0x000ffc00) >> 10) * 250;
var l3Volt_mV = ((lineVoltArr & 0x000003ff) >> 0) * 250;
if (l1Volt_mV != 0) {
l1Volt_mV += 20000;
}
if (l2Volt_mV != 0) {
l2Volt_mV += 20000;
}
if (l3Volt_mV != 0) {
l3Volt_mV += 20000;
}
return [l1Volt_mV, l2Volt_mV, l3Volt_mV];
}
function decodeCurrents(byteArr, startIdx) {
var lineCurrArr = arrToUint32(byteArr, startIdx);
return [
((lineCurrArr & 0x3ff00000) >> 20) * 100,
((lineCurrArr & 0x000ffc00) >> 10) * 100,
((lineCurrArr & 0x000003ff) >> 0) * 100,
];
}
obj.msgType = bytes[0];
obj.timeStamp = arrToUint32(bytes, 1);
// JS expects timestamp in milliseconds
var dateObj = new Date(obj.timeStamp * 1000);
obj.timeString =
dateObj.getUTCFullYear() +
"-" +
zfill(dateObj.getUTCMonth() + 1, 2) +
"-" +
zfill(dateObj.getUTCDate(), 2);
obj.timeString +=
" " +
zfill(dateObj.getUTCHours(), 2) +
":" +
zfill(dateObj.getUTCMinutes(), 2) +
":" +
zfill(dateObj.getUTCSeconds(), 2);
switch (obj.msgType) {
// Msg type 1
case 0x01: {
// Meter readings
obj.activeImportReading = arrToUint40(bytes, 5);
// Active power data, peak and averages
obj.actL1ImportPowerPeak = decodePower(arrToUint16(bytes, 10));
obj.actL1ImportPowerAver = decodePower(arrToUint16(bytes, 12));
obj.actL2ImportPowerPeak = decodePower(arrToUint16(bytes, 14));
obj.actL2ImportPowerAver = decodePower(arrToUint16(bytes, 16));
obj.actL3ImportPowerPeak = decodePower(arrToUint16(bytes, 18));
obj.actL3ImportPowerAver = decodePower(arrToUint16(bytes, 20));
// Line voltages
obj.l1VoltageAver_mV = decodeVoltages(bytes, 22)[0];
obj.l2VoltageAver_mV = decodeVoltages(bytes, 22)[1];
obj.l3VoltageAver_mV = decodeVoltages(bytes, 22)[2];
// Line currents
obj.l1CurrentPeak_mA = decodeCurrents(bytes, 26)[0];
obj.l2CurrentPeak_mA = decodeCurrents(bytes, 26)[1];
obj.l3CurrentPeak_mA = decodeCurrents(bytes, 26)[2];
break;
}
// Msg type 2
case 0x02: {
// Meter readings
obj.activeImportReading = arrToUint40(bytes, 5);
obj.activeExportReading = arrToUint40(bytes, 10);
// Active power data, peak and averages
obj.actL1ImportPowerPeak = decodePower(arrToUint16(bytes, 15));
obj.actL1ImportPowerAver = decodePower(arrToUint16(bytes, 17));
obj.actL2ImportPowerPeak = decodePower(arrToUint16(bytes, 19));
obj.actL2ImportPowerAver = decodePower(arrToUint16(bytes, 21));
obj.actL3ImportPowerPeak = decodePower(arrToUint16(bytes, 23));
obj.actL3ImportPowerAver = decodePower(arrToUint16(bytes, 25));
obj.actL1ExportPowerAver = decodePower(arrToUint16(bytes, 27));
obj.actL2ExportPowerAver = decodePower(arrToUint16(bytes, 29));
obj.actL3ExportPowerAver = decodePower(arrToUint16(bytes, 31));
// Line voltages
obj.l1VoltageAver_mV = decodeVoltages(bytes, 33)[0];
obj.l2VoltageAver_mV = decodeVoltages(bytes, 33)[1];
obj.l3VoltageAver_mV = decodeVoltages(bytes, 33)[2];
// Line current
obj.l1CurrentPeak_mA = decodeCurrents(bytes, 37)[0];
obj.l2CurrentPeak_mA = decodeCurrents(bytes, 37)[1];
obj.l3CurrentPeak_mA = decodeCurrents(bytes, 37)[2];
break;
}
// Msg type 3
case 0x03: {
// Meter readings
obj.activeImportReading = arrToUint40(bytes, 5);
obj.reactiveImportReading = arrToUint40(bytes, 10);
obj.reactiveExportReading = arrToUint40(bytes, 15);
// Active power data, peak and averages
obj.actL1ImportPowerAver = decodePower(arrToUint16(bytes, 20));
obj.actL2ImportPowerAver = decodePower(arrToUint16(bytes, 22));
obj.actL3ImportPowerAver = decodePower(arrToUint16(bytes, 24));
obj.reactL1ImportPowerAver = decodePower(arrToUint16(bytes, 26));
obj.reactL2ImportPowerAver = decodePower(arrToUint16(bytes, 28));
obj.reactL3ImportPowerAver = decodePower(arrToUint16(bytes, 30));
obj.reactL1ExportPowerAver = decodePower(arrToUint16(bytes, 32));
obj.reactL2ExportPowerAver = decodePower(arrToUint16(bytes, 34));
obj.reactL3ExportPowerAver = decodePower(arrToUint16(bytes, 36));
// Line voltages
obj.l1VoltageAver_mV = decodeVoltages(bytes, 38)[0];
obj.l2VoltageAver_mV = decodeVoltages(bytes, 38)[1];
obj.l3VoltageAver_mV = decodeVoltages(bytes, 38)[2];
// Line currents
obj.l1CurrentPeak_mA = decodeCurrents(bytes, 42)[0];
obj.l2CurrentPeak_mA = decodeCurrents(bytes, 42)[1];
obj.l3CurrentPeak_mA = decodeCurrents(bytes, 42)[2];
break;
}
// Msg type 4
case 0x04: {
// Meter readings
obj.activeImportReadingLowTariff = arrToUint40(bytes, 5);
obj.activeImportReadingNormTariff = arrToUint40(bytes, 10);
// Active power averages
obj.actL1ImportPowerAver = decodePower(arrToUint16(bytes, 15));
obj.actL2ImportPowerAver = decodePower(arrToUint16(bytes, 17));
obj.actL3ImportPowerAver = decodePower(arrToUint16(bytes, 19));
// Line voltages
obj.l1VoltageAver_mV = decodeVoltages(bytes, 21)[0];
obj.l2VoltageAver_mV = decodeVoltages(bytes, 21)[1];
obj.l3VoltageAver_mV = decodeVoltages(bytes, 21)[2];
// Line currents
obj.l1CurrentPeak_mA = decodeCurrents(bytes, 25)[0];
obj.l2CurrentPeak_mA = decodeCurrents(bytes, 25)[1];
obj.l3CurrentPeak_mA = decodeCurrents(bytes, 25)[2];
// Tariff indicator
obj.tariff = bytes[29];
break;
}
// Msg type 5
case 0x05: {
// Meter readings
obj.activeImportReadingLowTariff = arrToUint40(bytes, 5);
obj.activeImportReadingNormTariff = arrToUint40(bytes, 10);
obj.activeExportReadingLowTariff = arrToUint40(bytes, 15);
obj.activeExportReadingNormTariff = arrToUint40(bytes, 20);
// Active power averages
obj.actL1ImportPowerAver = decodePower(arrToUint16(bytes, 25));
obj.actL2ImportPowerAver = decodePower(arrToUint16(bytes, 27));
obj.actL3ImportPowerAver = decodePower(arrToUint16(bytes, 29));
obj.actL1ExportPowerAver = decodePower(arrToUint16(bytes, 31));
obj.actL2ExportPowerAver = decodePower(arrToUint16(bytes, 33));
obj.actL3ExportPowerAver = decodePower(arrToUint16(bytes, 35));
// Line voltages
obj.l1VoltageAver_mV = decodeVoltages(bytes, 37)[0];
obj.l2VoltageAver_mV = decodeVoltages(bytes, 37)[1];
obj.l3VoltageAver_mV = decodeVoltages(bytes, 37)[2];
// Line currents
obj.l1CurrentPeak_mA = decodeCurrents(bytes, 41)[0];
obj.l2CurrentPeak_mA = decodeCurrents(bytes, 41)[1];
obj.l3CurrentPeak_mA = decodeCurrents(bytes, 41)[2];
// Tariff indicator
obj.tariff = bytes[45];
break;
}
}
} else if (fPort === 10) {
obj.equipmentId = toHexString(bytes);
}
delete obj.timeStamp;
delete obj.timeString;
delete obj.msgType;
return { data: obj };
}