Hi, I have huge problems with a decoder.
I cannot find this problem - don’t know where to look / how to get it:
type:"UPLINK_CODEC"
error:"execute js error: js vm error: (anonymous): Line 2:53 Unexpected token = (and 9 more errors)"
The node is a heat meter only sending data every 2-3 hours which does not allow real trial and error approach. So far I have not found a dryrun environment…
Execution of the code via nodejs works perfekt.
//example payload: HgQG0jQBAAQTfa10AAIrAAACOwAAAlqCAgJeQwIHeTQGlnGlEUAEAf0XAA==
function Decode(fPort, bytes, variables) {
function decode_dib(bytes, index, extended_mode = false) {
var result = {};
var error = [];
var key = "undefined";
var dib = (bytes[index++] << 8) | bytes[index++]; //two byte identifier
switch (dib) {
//---ENERGY---
case 0x0403:
key = "energy";
result.unit = "Wh";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 1;
result.value = parseInt(result.value);
result["Wh"] = result.value;
break;
case 0x0404:
key = "energy";
result.unit = "Wh";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 10;
result.value = parseInt(result.value);
result["Wh"] = result.value;
break;
case 0x0405:
key = "energy";
result.unit = "Wh";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 100;
result.value = parseInt(result.value);
result["Wh"] = result.value;
break;
case 0x0406:
key = "energy";
result.unit = "kWh";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 1;
result.value = parseInt(result.value);
result["Wh"] = result.value * 1000;
break;
case 0x0407:
key = "energy";
result.unit = "kWh";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 10;
result.value = parseInt(result.value);
result["Wh"] = result.value * 1000;
break;
case 0x040e:
key = "energy";
result.unit = "MJ";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 1;
result["Wh"] = result.value * 277.8;
break;
case 0x040f:
key = "energy";
result.unit = "MJ";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 10;
result["Wh"] = result.value * 277.8;
break;
//---VOLUME---
case 0x413:
key = "volume";
result.unit = "m³";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 0.001;
result["m³"] = result.value * 1;
break;
case 0x414:
key = "volume";
result.unit = "m³";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 0.01;
result["m³"] = result.value * 1;
break;
case 0x415:
key = "volume";
result.unit = "m³";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 0.1;
result["m³"] = result.value * 1;
break;
case 0x416:
key = "volume";
result.unit = "m³";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 1;
result["m³"] = result.value * 1;
break;
case 0x417:
key = "volume";
result.unit = "m³";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 10;
result["m³"] = result.value * 1;
break;
//---POWER---
case 0x022b:
key = "power";
result.unit = "W";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 1;
result["W"] = result.value * 1;
break;
case 0x022c:
key = "power";
result.unit = "W";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 10;
result["W"] = result.value * 1;
break;
case 0x022d:
key = "power";
result.unit = "W";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 100;
result["W"] = result.value * 1;
break;
case 0x022e:
key = "power";
result.unit = "kW";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 1;
result["W"] = result.value * 1000;
break;
case 0x022f:
key = "power";
result.unit = "kW";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 10;
result["W"] = result.value * 1000;
break;
//---FLOW---
case 0x023b:
key = "flow";
result.unit = "m³/h";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 0.001;
result["m³/h"] = result.value * 1;
break;
case 0x023c:
key = "flow";
result.unit = "m³/h";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 0.01;
result["m³/h"] = result.value * 1;
break;
case 0x023d:
key = "flow";
result.unit = "m³/h";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 0.1;
result["m³/h"] = result.value * 1;
break;
case 0x023e:
key = "flow";
result.unit = "m³/h";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 1;
result["m³/h"] = result.value * 1;
break;
case 0x023f:
key = "flow";
result.unit = "m³/h";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 10;
result["m³/h"] = result.value * 1;
break;
//--FW_TEMP--
case 0x0258:
key = "fw_temp";
result.unit = "°C";
result.value = ((bytes[index++] | (bytes[index++] << 8)) * 0.001).toFixed(3) * 1;
result["°C"] = result.value * 1;
break;
case 0x0259:
key = "fw_temp";
result.unit = "°C";
result.value = ((bytes[index++] | (bytes[index++] << 8)) * 0.01).toFixed(2) * 1;
result["°C"] = result.value * 1;
break;
case 0x025a:
key = "fw_temp";
result.unit = "°C";
result.value = ((bytes[index++] | (bytes[index++] << 8)) * 0.1).toFixed(1) * 1;
result["°C"] = result.value * 1;
break;
case 0x025b:
key = "fw_temp";
result.unit = "°C";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 1;
result["°C"] = result.value * 1;
break;
//--RT_TEMP--
case 0x025c:
key = "rt_temp";
result.unit = "°C";
result.value = ((bytes[index++] | (bytes[index++] << 8)) * 0.001).toFixed(3) * 1;
result["°C"] = result.value * 1;
break;
case 0x025d:
key = "rt_temp";
result.unit = "°C";
result.value = ((bytes[index++] | (bytes[index++] << 8)) * 0.01).toFixed(2) * 1;
result["°C"] = result.value * 1;
break;
case 0x025e:
key = "rt_temp";
result.unit = "°C";
result.value = ((bytes[index++] | (bytes[index++] << 8)) * 0.1).toFixed(1) * 1;
result["°C"] = result.value * 1;
break;
case 0x025f:
key = "rt_temp";
result.unit = "°C";
result.value = parseInt(bytes[index++] | (bytes[index++] << 8)) * 1;
result["°C"] = result.value * 1;
break;
//---DATUM TIME---
case 0x046d:
key = "meter_date_time";
//TODO: Date/Time encoding!
result.value = bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32);
break;
case 0x346d:
key = "meter_date_time";
result.value = null;
error.push("invalid date time reading");
//---ENERGY CONSUMPTION---
case 0x4403:
key = "accumulated_energy_at_2400";
result.unit = "Wh";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 1;
result["Wh"] = result.value * 1;
break;
case 0x4404:
key = "accumulated_energy_at_2400";
result.unit = "Wh";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 10;
result["Wh"] = result.value * 1;
break;
case 0x4405:
key = "accumulated_energy_at_2400";
result.unit = "Wh";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 100;
result["Wh"] = result.value * 1;
break;
case 0x4406:
key = "accumulated_energy_at_2400";
result.unit = "kWh";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 1;
result["Wh"] = result.value * 1000;
break;
case 0x4407:
key = "accumulated_energy_at_2400";
result.unit = "kWh";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 10;
result["Wh"] = result.value * 1000;
break;
case 0x440e:
key = "accumulated_energy_at_2400";
result.unit = "MJ";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 1;
result["Wh"] = result.value * 277.8;
break;
case 0x440f:
key = "accumulated_energy_at_2400";
result.unit = "MJ";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 10;
result["Wh"] = result.value * 277.8;
break;
default: //three byte identifier
dib = (dib << 8) | bytes[index++];
switch (dib) {
case 0x04fb0d:
key = "energy";
result.unit = "MCal";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 1;
result["Wh"] = result.value * 1164;
break;
case 0x04fb0e:
key = "energy";
result.unit = "MCal";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 10;
result["Wh"] = result.value * 1164;
break;
case 0x04fb0f:
key = "energy";
result.unit = "MCal";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 100;
result["Wh"] = result.value * 1164;
break;
case 0x44fb0d:
key = "accumulated_energy_at_2400";
result.unit = "MCal";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 1;
result["Wh"] = result.value * 1164;
break;
case 0x44fb0e:
key = "accumulated_energy_at_2400";
result.unit = "MCal";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 10;
result["Wh"] = result.value * 1164;
break;
case 0x44fb0f:
key = "accumulated_energy_at_2400";
result.unit = "MCal";
result.value = (bytes[index++] | (bytes[index++] << 8) | (bytes[index++] << 16) | (bytes[index++] << 32)) * 100;
result["Wh"] = result.value * 1164;
break;
case 0x07ffa0:
if (extended_mode) {
break;
}
case 0x01fd17:
key = "error_message";
result.value = bytes[index++];
error.push("error code: " + String(result.value));
break;
default:
//without any identifier - this should be meter_id!
if (extended_mode) {} else {
//console.log(index, bytes.length, bytes.length - 4 - index);
var offset = 4;
var tmp = [];
key = "meter_address";
result.dif_vif = String(bytes[index++]) + " " + String(bytes[index++]);
tmp[3] = bytes[index++];
tmp[2] = bytes[index++];
tmp[1] = bytes[index++];
tmp[0] = bytes[index++];
result.id = bytesToHexString(tmp);
var left_bytenumber = bytes.length - index - offset;
result.manufacturer = bytes.length - index - offset > 1 ? String(bytes[index++]) + " " + String(bytes[index++]) : null;
result.version = bytes.length - index - offset > 0 ? String(bytes[index++]) : null;
result.device_type = bytes.length - index - offset > 0 ? String(bytes[index++]) : null;
}
}
}
return [key, result, error, index];
}
function bytesToHexString(bytes) {
var res = [];
for (var i = 0; i < bytes.length; i++) {
//console.log("bytestoheycode", bytes, i);
var hex = bytes[i].toString(16);
if (hex.length < 2) {
hex = "0" + hex;
}
res.push(hex);
}
return res.join("");
}
var data = {};
data.fPort = fPort;
data.bytes = bytes;
data.bytelength = bytes.length;
data.variables = variables;
data.error = [];
data.message_format='';
var index = 0;
var tmp_result;
switch (bytes[index++]) {
case 0x1e:
data.message_format = "standard";
break;
case 0x1f:
data.message_format = "compact";
break;
case 0x20:
data.message_format = "json";
data.json = bytes;
break;
case 0x21:
data.message_format = "scheduled-daily redundant";
break;
case 0x22:
data.message_format = "scheduled-extended";
break;
case 0x23:
data.message_format = "combined heat/cooling";
break;
case 0xfa:
data.message_format = "clock message";
break;
default:
data.message_format = "err";
data.error.push("unknown message format: " + String(bytes[index - 1]));
}
if (data.message_format.length > 4) {
do {
[key, tmp_result, error, index] = decode_dib(bytes, index);
error.length ? data.error.push(error) : null;
data[key] = tmp_result;
} while (index < data.bytelength);
}
return data;
}