TypeError: Cannot create property 'accX' on string '-0.009'

My own node outputs an object non-stop in order. The below figure shows the first 3 outputs. Then it repeats with new values:

nodeOutput

I would like to get 3 decimals points only hence, I have written the below function:

var newMsg = {};
newMsg = msg;

for(var value in newMsg.payload){
    if(typeof newMsg.payload[value] == 'number'){
        newMsg.payload[value] = newMsg.payload[value].toFixed(3);
    } else if(typeof newMsg.payload[value] == 'string'){
        newMsg.payload[value] = parseFloat(newMsg.payload[value]).toFixed(3);
    }
}
return newMsg;

I tested via injecting an example object. Everything works fine. However, if I connect it to my own node which generates an output seen in the first figure, I am getting the error in the title after it works fine for the first three inputs.

That does not create a new message object, as javascript uses references to refer to objects. newMsg will just be effectively a pointer to the original message. However, I don't think it should matter in this case. I don't immediately see what the error in the code is.

In fact all you need for the code is

for(const key in msg.payload){
    msg.payload[key] = Number(msg.payload[key]).toFixed(3)
}
return msg;

The Number() function will cope with a string or a number.
Note that the result of this code (and your original) is that the properties will all be strings, not numbers.

I have to ask why you want to do this though. It is usually a bad idea to throw away accuracy unless there is a good need to do so. Usually the time you need to do this is when it being displayed, and that is the time to round it.

I have to ask why you want to do this though. It is usually a bad idea to throw away accuracy unless there is a good need to do so. Usually the time you need to do this is when it being displayed, and that is the time to round it.

The sensor itself actually generates data with two decimals. Example output from my Arduino:

Acc. Subscription Status: 0
gyroX = -0.18 dps
gyroY = -2.26 dps
gyroZ = 0.24 dps
Gyro. Subscription Status: 0
magX = 0.84 uT
magY = 16.14 uT
magZ = 46.19 uT
Mag. Subscription Status: 0
AccX = 0.00 G
AccY = -0.02 G
AccZ = 1.02 G

To send this data over BLE I need to convert to byte and reconvert to float again. When I reconvert to float: let buffer = Buffer.from(data[i]).readFloatLE(0);, I am getting value high decimal numbers.

I am getting a similar error with your code as well:
Cannot set properties of undefined (setting 'gyroX')
My guess is my own node is generating undefined data maybe? But when I print it via debug node, everything seems perfectly fine.

What does that (or another one you know the original value for) appear as after the conversion. It sounds as if the conversion is not correct.
Add this after the for line

node.warn(`key: ${key},  value: ${msg.payload[key]}`)

and see what it shows in the debug pane.

Also paste the function that you are now using.

The device I am using is Arduino Nano 33 BLE Sense. It has the LSM9DS1 sensor. The main library is LSM9DS1.cpp. I am reading the data via pre-defined functions from Arduino's library.. Here is how I read the data. This one generates data with 2 decimal points:

if(IMU.gyroscopeAvailable()){
    IMU.readGyroscope(x, y, z);
    gyroData.values[0] = x; // 0.11
    gyroData.values[1] = y; // 1.13
    gyroData.values[2] = z; // -1.13
    gyroData.updated = true;
  }

This is how they generate in the source code:

int LSM9DS1Class::readGyroscope(float& x, float& y, float& z)
{
  int16_t data[3];
  if (!readRegisters(LSM9DS1_ADDRESS, LSM9DS1_OUT_X_G, (uint8_t*)data, sizeof(data))) {
    x = NAN;
    y = NAN;
    z = NAN;
    return 0;
  }
  x = data[0] * 2000.0 / 32768.0;
  y = data[1] * 2000.0 / 32768.0;
  z = data[2] * 2000.0 / 32768.0;
  return 1;
}

Honestly, I don't know much to verify how accurate is that. I am sending this data over BLE where we cannot send multiple sensor float data (we cannot send float array). Hence I need to convert those to byte first then reconvert to float.

When I add the warn there I did not get any errors. This is the function node:

for(const key in msg.payload){
    node.warn(`key: ${key},  value: ${msg.payload[key]}`);
    msg.payload[key] = Number(msg.payload[key]).toFixed(3);
}
return msg;

This is from the Node-RED log which keeps repeating:

29 Nov 16:00:49 - [warn] [function:rounder] key: gyroX,  value: -0.244140625
29 Nov 16:00:49 - [warn] [function:rounder] key: gyroY,  value: -2.197265625
29 Nov 16:00:49 - [warn] [function:rounder] key: gyroZ,  value: 0.1220703125
29 Nov 16:00:49 - [warn] [function:rounder] key: accX,  value: -0.0068359375
29 Nov 16:00:49 - [warn] [function:rounder] key: accY,  value: -0.0093994140625
29 Nov 16:00:49 - [warn] [function:rounder] key: accZ,  value: 1.01953125
29 Nov 16:00:49 - [warn] [function:rounder] key: magX,  value: 3.271484375
29 Nov 16:00:49 - [warn] [function:rounder] key: magY,  value: 21.435546875
29 Nov 16:00:49 - [warn] [function:rounder] key: magZ,  value: 46.6552734375

I am very confused tbh.

So where is the error?

It should print one set out for each message going in.

On the conversion, can you give an example of what the sensor reads as and what that converts to by the time it gets to node-red. That is the only way of knowing if it is working correctly.

[Edit] Sorry, just saw that you said it now doesn't show an error. The node.warn won't make any difference to whether there is an error or not.

I have been looking at the Arduino code and can't see why that would only give you two decimal places. For example a value of 2 in data[0] would give 2 * 2000 / 32768 which is 0.122070313 which is what gyroZ is showing as in the third line of the log you showed. Similarly -4 would give -0.244140625 which is what the first line in the log has. So I think the values in node-red are correct, it is the logging in the arduino that is only showing 2 digits that is wrong.

It should print one set out for each message going in.

This is what I meant sorry. I commented the warning, it still works as expected.

Sorry, just saw that you said it now doesn't show an error. The node.warn won't make any difference to whether there is an error or not.

Probably, I forgot to deploy after editing the function node. Otherwise, I can't explain this.

So I printed the data as soon as I read:

  if(IMU.accelerationAvailable()){
    IMU.readAcceleration(x, y, z);
    accData.values[0] = x; 
    accData.values[1] = y; 
    accData.values[2] = z; 
    accData.updated = true;
    Serial.print("AccX: ");
    Serial.println(x); // prints 0.01 etc.
    Serial.println(x, 5) // prints 5 decimals etc.
  }

So I think the values in node-red are correct, it is the logging in the arduino that is only showing 2 digits that is wrong.

Exactly as you suspected. So it seems Serial.print(x); defaults to two decimals. I can see the full value when I print as Serial.print(x, 6) etc.

Thanks for all the help, now I understand better.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.