MQTT Telegraf to decode before insertion

{“msg_id”:3070,“device_info”:{“mac”:“40915188c970”},“data”:[{“timestamp”:1701060326565,“timezone”:11,“adv_data”:“0201060303aafe0c16aafe2101070e211bcbff00”,“rsp_data”:“091680206f010000000007097a6f6d61746f”,“type_code”:10,“type”:“other”,“rssi”:-57,“connectable”:1,“mac”:“bc5729009415”},{“timestamp”:1701060326579,“timezone”:11,“adv_data”:“0201060303aafe1216aafe21010f0be51b933ab4002effb203d8”,“rsp_data”:“091680206801000000000d094b4250726f5f333734323739”,“type_code”:10,“type”:“other”,“rssi”:-67,“connectable”:1,“mac”:“bc572902a655”},{“timestamp”:1701060326888,“timezone”:11,“adv_data”:“0201060303aafe0b16aafe2100230c0e1b4001”,“rsp_data”:“091680206c010000000010095049522d524f4f4d5f343236333030”,“type_code”:10,“type”:“other”,“rssi”:-48,“connectable”:1,“mac”:“bc572904f039”},{“timestamp”:1701060327082,“timezone”:11,“adv_data”:“0201060303aafe1216aafe21010f0bdf1c0438be007d003e03f7”,“rsp_data”:“091680206701000000000d094b4250726f5f333938323338”,“type_code”:10,“type”:“other”,“rssi”:-61,“connectable”:1,“mac”:“bc572903f5d5”},{“timestamp”:1701060327412,“timezone”:11,“type_code”:6,“type”:“bxp-th”,“rssi”:-82,“connectable”:1,“mac”:“ce48e37ed75c”,“txpower”:0,“ranging_data”:0,“adv_interval”:1000,“temperature”:29.4,“humidity”:69.2,“batt_vol”:2519}]}

adv_data":“0201060303aafe0c16aafe2101070e211bcbff00”
“rsp_data”:"091680206c010000000010095049522d524f4f4d5f343236333030

The adv data contains temperature , humidity , light , co2, x,y,z

Till now i was using node red to extract and insert into influxdb.

is there any better option like using Telegraf .

Yeh take a look here

how to write custom functions to convert hex to 8.8 floating point as it is required to convert before writing to the database (timeseries )

This may not be an exact solution , but it sounds pretty close.

Take a look at this comment, and the reply to it

// Extract the required data from the payload
const data = msg.payload.data.map(item => {
const temperature = Number(hexTo8p8(item.adv_data.substr(32, 4)));
const humidity = Number(hexTo8p8(item.adv_data.substr(36, 4)));

return {
    adv_data: item.adv_data,
    rssi: item.rssi,
    mac: item.mac.toUpperCase(),
    timestamp: item.timestamp,


};

});

var structure = [
{ name: “AdvFlags”, offset: 0, length: 3 },
{ name: “ID”, offset: 4, length: 3 },
{ name: “AdvType”, offset: 8, length: 1 },
{ name: “UUID”, offset: 9, length: 2 },
{ name: “FrameType”, offset: 11, length: 1 },
{ name: “VersionTag”, offset: 12, length: 1 },
{ name: “SensorMask”, offset: 13, length: 1 },
{ name: “Voltage”, offset: 14, length: 2 },
{ name: “Temperature”, offset: 16, length: 2 },
{ name: “Humidity”, offset: 18, length: 2 },
{ name: “AccX”, offset: 20, length: 2 },
{ name: “AccY”, offset: 22, length: 2 },
{ name: “AccZ”, offset: 24, length: 2 },
{ name: “CutoffFlag”, offset: 26, length: 1 },
{ name: “PIRFlag”, offset: 27, length: 1 }
];
// Extract values based on the provided structure
// Initialize an array to store data points for bulk insert
var influxBulkInsert = ;

// Format the data for InfluxDB
const influxData = data.map(item => {

var sensorMask = parseInt(item.adv_data.substr(13 * 2, 2), 16);



var dataPoint = {
    measurement: 'mem',
    fields: {
        rssi: item.rssi,
        device_mac: item.mac.toUpperCase(),
        sensor_mask: parseInt(item.adv_data.substr(13 * 2, 2), 16),
        Voltage: parseInt(item.adv_data.substr(14 * 2, 4), 16),
        raw: item.adv_data
    },
    tags: {
        mac: item.mac.toUpperCase(),
        device_mac: item.mac.toUpperCase(),
        sensor_mask: parseInt(item.adv_data.substr(13 * 2, 2), 16),
    },
    timestamp: item.timestamp

};

// Check if CutoffBit is true (Bit 4)
if (sensorMask & 0x10) {
    dataPoint.fields.cutoff = parseInt(item.adv_data.substr(13 * 2, 2), 16);
}
// Check each bit in the sensor mask
if (sensorMask & 0x01) {
    // Bit 0: Voltage
    dataPoint.fields.voltage = parseInt(item.adv_data.substr(14 * 2, 4), 16);
}

if (sensorMask & 0x02) {
    // Bit 1: Temperature
    dataPoint.fields.temperature = Number(hexTo8p8(item.adv_data.substr(32, 4)));
}

if (sensorMask & 0x04) {
    // Bit 2: Humidity
    dataPoint.fields.humidity = Number(hexTo8p8(item.adv_data.substr(36, 4)));
}

if (sensorMask & 0x08) {
    // Bit 3: Accelerometer
    dataPoint.fields.AccX = parseInt(item.adv_data.substr(20 * 2, 4), 16);
    dataPoint.fields.AccY = parseInt(item.adv_data.substr(22 * 2, 4), 16);
    dataPoint.fields.AccZ = parseInt(item.adv_data.substr(24 * 2, 4), 16);
}

if (sensorMask & 0x10) {
    // Bit 4: Cutoff
    dataPoint.fields.cutoff = parseInt(item.adv_data.substr(18 * 2, 2), 16);
}

if (sensorMask & 0x20) {
    // Bit 5: PIR Indication
    // Include PIR indication field if the bit is set
    dataPoint.fields.PIRIndication = parseInt(item.adv_data.substr(14 * 2, 2), 16);
}


influxBulkInsert.push(dataPoint);

});

// Set the formatted data as the new payload
msg.payload = influxBulkInsert;
return msg;

function hexTo8p8(/** @type {string} */ value) {
let intValue = parseInt(value, 16);
let signed = (intValue & 0x8000) > 0 ? -1 / 10 : 1;
return signed * intValue / Math.pow(2, 8);
}

// Convert Temperature and Humidity from hex to 8.8 fixed-point format
[“Temperature”, “Humidity”].forEach(function (field_name) {
extractedValues[field_name] = parseInt(extractedValues[field_name], 16) / 256.0;
});

// Extract and interpret the Sensor Mask bits
var sensor_mask = parseInt(extractedValues.SensorMask, 16);
extractedValues.VoltageBit = !!(sensor_mask & 0x01);
extractedValues.TempBit = !!(sensor_mask & 0x02);
extractedValues.HumidityBit = !!(sensor_mask & 0x04);
extractedValues.AccBit = !!(sensor_mask & 0x08);
extractedValues.CutoffBit = !!(sensor_mask & 0x10);
extractedValues.PIRIndicationBit = !!(sensor_mask & 0x20);

function hexTo8p8(/** @type {string} */ value) {
let intValue = parseInt(value, 16);
let signed = (intValue & 0x8000) > 0 ? -1 / 10 : 1;
return signed * intValue / Math.pow(2, 8);
}

Need some support to convert this function for Telefraf for converitng raw adv data