Hello everyone,
After reviewing the Heltec documentation in detail and going through several iterations of testing, I was able to develop my own solution for decoding the data from the Heltec HRI-3621 sensor. Rather than relying on the Heltec-provided example code, I built a custom decoder that works well for me.
For those who are interested, I’ve created a Node-Red function that decodes and displays the Base64 data, and I’ve also built a custom codec for ChirpStack that handles the sensor’s data correctly.
Here is an example of the Node-Red function that decodes the Base64 data:
// Ensure the payload is a string
if (typeof msg.payload.data === 'string') {
// Decode Base64 data to a byte array
let bytes = Buffer.from(msg.payload.data, 'base64');
// Function to convert 4 bytes to a float (Little Endian)
function bytesToFloat(by) {
var buffer = Buffer.from(by);
return buffer.readFloatLE(0);
}
// Initialize variables for pressure and temperature
let temperature = null;
let pressure = null;
// Identify sensor sub-IDs and assign the correct data types
let sensorDataIndex = 0;
while (sensorDataIndex < bytes.length) {
let subId = bytes[sensorDataIndex] >> 4; // Upper 4 bits for Sub-ID
let dataType = bytes[sensorDataIndex] & 0x0F; // Lower 4 bits for data type
// Shift index after reading the first byte
sensorDataIndex++;
// Decode based on Sub-ID and data type
if (subId === 0x00 && dataType === 0b0010) {
// Sub-ID 0x00 -> Pressure, data type: float (4 bytes)
pressure = bytesToFloat(bytes.slice(sensorDataIndex, sensorDataIndex + 4));
sensorDataIndex += 4; // Shift past float data
} else if (subId === 0x01 && dataType === 0b0010) {
// Sub-ID 0x01 -> Temperature, data type: float (4 bytes)
temperature = bytesToFloat(bytes.slice(sensorDataIndex, sensorDataIndex + 4));
sensorDataIndex += 4; // Shift past float data
} else {
// Skip unknown data types or Sub-IDs
sensorDataIndex++;
}
}
// Format and output decoded data
msg.payload = {
temperature: temperature !== null ? temperature.toFixed(2) + " °C" : "N/A",
pressure: pressure !== null ? pressure.toFixed(2) + " hPa" : "N/A",
rawBytes: Buffer.from(bytes).toString('hex') // Raw bytes as hex string
};
return msg; }
else {
// Error handling for invalid data types
node.error("Received data is not a Base64 string.");
return null;
}
Additionally, I’ve written a custom codec for ChirpStack that works with the Heltec HRI-3621 sensor. If anyone is interested, I’m happy to share this codec and provide further explanations.
function decodeUplink(input) {
// Base64 data as a byte array
let bytes = input.bytes;
// Function to convert 4 bytes into a float (Little Endian)
function bytesToFloat(by) {
// Convert bytes into an integer
let bits = (by[0]) | (by[1] << 8) | (by[2] << 16) | (by[3] << 24);
let sign = (bits >>> 31 === 0) ? 1.0 : -1.0;
let e = (bits >>> 23) & 0xff;
let m = (e === 0) ? (bits & 0x7fffff) << 1 : (bits & 0x7fffff) | 0x800000;
let floatVal = sign * m * Math.pow(2, e - 150);
return floatVal;
}
// Initialize variables for pressure and temperature
let temperature = null;
let pressure = null;
// Identify sensor sub-IDs and assign the corresponding data types
// Sub-ID for pressure (0x00) and temperature (0x01)
let sensorDataIndex = 0;
while (sensorDataIndex < bytes.length) {
// Extract the sub-ID and data type from the first byte
let subId = bytes[sensorDataIndex] >> 4; // Upper 4 bits for sub-ID
let dataType = bytes[sensorDataIndex] & 0x0F; // Lower 4 bits for data type
// Determine the start index of the sensor data
sensorDataIndex++;
// Process based on sub-ID and data type
if (subId === 0x00 && dataType === 0b0010) {
// Sub-ID: 0x00 -> Pressure, Data type: Float (4 bytes)
pressure = bytesToFloat(bytes.slice(sensorDataIndex, sensorDataIndex + 4));
sensorDataIndex += 4; // Move forward after the float data type
} else if (subId === 0x01 && dataType === 0b0010) {
// Sub-ID: 0x01 -> Temperature, Data type: Float (4 bytes)
temperature = bytesToFloat(bytes.slice(sensorDataIndex, sensorDataIndex + 4));
sensorDataIndex += 4; // Move forward after the float data type
} else {
// Skip if an unknown data type or sub-ID is found
sensorDataIndex++; // Skip 1 byte to continue
}
}
// Return the decoded data to ChirpStack
return {
data: {
temperature: temperature !== null ? temperature.toFixed(2) + " °C" : "N/A",
pressure: pressure !== null ? pressure.toFixed(2) + " hPa" : "N/A"
}
};
}
Summary
This text will be hidden
Best regards,
Niox