Hi Leandro,
I’ve created the following parser to help you decode the data you’re receiving:
/**
* Parses device telemetry data and converts it to TagoIO format
*
* @param {Object} deviceData - The device telemetry object
* @param {string} group - Group identifier for related data
* @param {string} receivedTime - Time when data was received
* @returns {Array} Array of TagoIO data objects
*/
function parseDeviceTelemetry(deviceData, group, receivedTime) {
const data = [];
const time = receivedTime || new Date().toISOString();
// Device identification information
if (deviceData.IMEI) {
data.push({
variable: "imei",
value: deviceData.IMEI,
group,
time,
metadata: {
device_model: deviceData.Model || "Unknown"
}
});
}
if (deviceData.IMSI) {
data.push({
variable: "imsi",
value: deviceData.IMSI,
group,
time
});
}
if (deviceData.Model) {
data.push({
variable: "device_model",
value: deviceData.Model,
group,
time
});
}
// Battery level
if (deviceData.battery !== undefined) {
data.push({
variable: "battery",
value: deviceData.battery,
unit: "V",
group,
time,
metadata: {
battery_status:
deviceData.battery > 3.5
? "Good"
: deviceData.battery > 3.2
? "Low"
: "Critical"
}
});
}
// Signal strength
if (deviceData.signal !== undefined) {
data.push({
variable: "signal_strength",
value: deviceData.signal,
unit: "dBm",
group,
time,
metadata: {
signal_quality:
deviceData.signal > 20
? "Excellent"
: deviceData.signal > 15
? "Good"
: deviceData.signal > 10
? "Fair"
: "Poor"
}
});
}
// Module information
if (deviceData.mod !== undefined) {
data.push({
variable: "module_id",
value: deviceData.mod,
group,
time
});
}
// ADC reading
if (deviceData.adc2 !== undefined) {
data.push({
variable: "adc2",
value: deviceData.adc2,
unit: "V",
group,
time
});
}
// Temperature sensor (DS18B20)
if (deviceData.DS18B20_Temp !== undefined) {
// Check if temperature reading is valid (not error value like -409.5)
const isValidTemp =
deviceData.DS18B20_Temp > -200 && deviceData.DS18B20_Temp < 200;
data.push({
variable: "temperature",
value: isValidTemp ? deviceData.DS18B20_Temp : null,
unit: "°C",
group,
time,
metadata: {
sensor_type: "DS18B20",
sensor_status: isValidTemp ? "OK" : "Error",
raw_value: deviceData.DS18B20_Temp
}
});
// Add sensor status as separate variable for monitoring
data.push({
variable: "temperature_sensor_status",
value: isValidTemp ? "OK" : "Error",
group,
time,
metadata: {
error_code: isValidTemp ? null : "TEMP_SENSOR_ERROR",
raw_reading: deviceData.DS18B20_Temp
}
});
}
// Interrupt monitoring
if (deviceData.interrupt !== undefined) {
data.push({
variable: "interrupt",
value: deviceData.interrupt,
group,
time,
metadata: {
interrupt_level: deviceData.interrupt_level || 0
}
});
}
if (deviceData.interrupt_level !== undefined) {
data.push({
variable: "interrupt_level",
value: deviceData.interrupt_level,
group,
time
});
}
// PA4 interrupt monitoring
if (deviceData.interrupt_pa4 !== undefined) {
data.push({
variable: "interrupt_pa4",
value: deviceData.interrupt_pa4,
group,
time,
metadata: {
interrupt_level_pa4: deviceData.interrupt_level_pa4 || 0
}
});
}
if (deviceData.interrupt_level_pa4 !== undefined) {
data.push({
variable: "interrupt_level_pa4",
value: deviceData.interrupt_level_pa4,
group,
time
});
}
// PA8 interrupt monitoring
if (deviceData.interrupt_pa8 !== undefined) {
data.push({
variable: "interrupt_pa8",
value: deviceData.interrupt_pa8,
group,
time,
metadata: {
interrupt_level_pa8: deviceData.interrupt_level_pa8 || 0
}
});
}
if (deviceData.interrupt_level_pa8 !== undefined) {
data.push({
variable: "interrupt_level_pa8",
value: deviceData.interrupt_level_pa8,
group,
time
});
}
// Device timestamp (if different from received time)
if (deviceData.time) {
// Convert device time format to ISO string if needed
let deviceTime;
try {
// Handle the format "2025/03/15 16:55:01"
const timeStr = deviceData.time.replace(/\//g, "-");
deviceTime = new Date(timeStr).toISOString();
} catch (error) {
deviceTime = time; // Fallback to received time
}
data.push({
variable: "device_timestamp",
value: deviceData.time,
group,
time: deviceTime,
metadata: {
original_format: deviceData.time,
parsed_time: deviceTime
}
});
}
return data;
}
// Main decoder logic
try {
// Check if payload contains the device data
const deviceDataItem = payload.find(
(item) =>
item.variable === "payload" ||
item.variable === "data" ||
(item.value && typeof item.value === "object")
);
if (deviceDataItem) {
let deviceData;
// Parse JSON if the value is a string
if (typeof deviceDataItem.value === "string") {
try {
deviceData = JSON.parse(deviceDataItem.value);
} catch (error) {
console.error("Failed to parse JSON payload:", error.message);
payload = [
{ variable: "parser_error", value: "Invalid JSON format", time: new Date().toISOString() }
];
}
} else if (typeof deviceDataItem.value === "object") {
deviceData = deviceDataItem.value;
}
if (deviceData) {
// Generate group ID for related data
const group = deviceDataItem.group || `${Date.now()}-${Math.random().toString(36).substring(2, 5)}`;
// Parse the device data
const parsedData = parseDeviceTelemetry(deviceData, group, deviceDataItem.time);
// Replace payload with parsed data
payload = parsedData;
}
} else {
// If no structured payload found, try to parse the entire payload as device data
if (payload.length > 0 && payload[0].value && typeof payload[0].value === "object") {
const group = `${Date.now()}-${Math.random().toString(36).substring(2, 5)}`;
const parsedData = parseDeviceTelemetry(payload[0].value, group, payload[0].time);
payload = parsedData;
}
}
} catch (error) {
console.error("Payload parsing error:", error.message);
payload = [
{
variable: "parser_error",
value: `Parsing failed: ${error.message}`,
time: new Date().toISOString()
}
];
}
Please note that the code is expecting that json to be inside the payload variable’s value property, if its not, you’ll need to slightly modify the decoder.