How best to extract data from 'nested' objects (or flatten the message)?

I have an incoming MQTT message payload which looks like this:

"payload":
{"Time":"2024-10-13T16:43:17",
"DS18B20-1":{"Id":"030197946C6B","Temperature":36.8},
"DS18B20-2":{"Id":"0302979458D1","Temperature":44.7},
"DS18B20-3":{"Id":"030E97942425","Temperature":34.2},"TempUnit":"C"}

I wish to extract each 'Id' and its associated 'Temperature' - the Id checks against a table in GlobalContext, which swaps 'Id' for some human-readable description, and applies a calibration adjustment to the 'Temperature' value.

The function I'm using is below - but it fails because it doesn't 'drill through' each "DS18B20-x" heading. Do I /really/ need to write a separate function for each sub-object?

const sensorId=msg.payload.Id
const rawTemp=msg.payload.Temperature
const metadata=global.get('SensorTable')

if (metadata[sensorId]){
    msg.topic=metadata[sensorId].SensorLoc
    msg.payload = (rawTemp + metadata[sensorId].apply_offset).toFixed(1)
}

return msg;

Something like this might work
it will extract each reading, providing its an object
(but you should check, its the object you need - just a bit of sanity checking)

for (const [key, value] of Object.entries(msg.payload)) {
    if (typeof value === 'object') {
        const tempReading = {
            device: key,              /* DS18B20-1 */
            id: value.Id,             /* 030197946C6B */
            temp: value.Temperature   /* 36.8 */
        }
        // store/match/use tempReading somewhere (it will repeat for each object)
       // example : tempReading.id
    }
}

I would also add, for good coding habit please pick a variable naming convention.
Underscores: date_of_birth
PascalCase: DateOfBirth
camelCase: dateOfBirth
etc
Please try not to mix 3 different types in a piece of code it makes it unpleasant to edit, as you can not remember what each vars convention should be.

1 Like