Arduino gives SyntaxError: Unexpected token � in JSON, in a JS application

Sorry in advance for any confusion, this is my first project involving arduino and raspberry Pi.

Im currently working on a project called weatherStation where I'm recieving multiple data from my arduino which sends the data in JSON format to the raspberry pi. The goal is to build an application that can start up on raspberry PI in kiosk mode and then get the data from the arduino. The problem we have is that when we reboot the PI, our whole string gets cut short somehow. When we start up the program again, it doesnt understand the JSON format because obviously, half the string is missing and the program fails.

Our goal is to recieve the data as such

{"windSpeed": "0.00", "windDir": "NE", "windFloat": "45.00", "waterAmount": "0.00", "temperatureValue" : "0.00", "pressureValue" : "0.00", "humidityValue" : "0.00", "gasValue" : "0.00"}

Sometimes when we start the program, this is what we get and then our program fails because it does not understand the JSON format. Sometimes it does work, but its like 2,5 out of 10 times

{"ue" : "0.00", "pressureValue" : "0.00", "humidityValue" : "0.00", "gasValue" : "0.00"}
, "waterAmount": "0.00", "temperatureValue" : "0.00", "pressureValue" : "0.00", "humidityValue" : "0.00", "gasValue" : "0.00"}

{"windSpeed": "0.00", "windDir": "NE", "windFloat": "45.00", "waterAmount": "0.00", "temperatureValue" : "0.00", "pressureValue" : "0.00", "humidityValue" : "0.00", "gasValue" : "0.00"}

{"windSpeed": "0.00", "windDir": "NE", "windFloat": "45.00", "waterAmount": "0.00", "temperatureValue" : "0.00", "pressureValue" : "0.00", "humidityValue" : "0.00", "gasValue" : "0.00"}

This is the code we have in the arduino

 // Instantiere globale variabler
int windDirPin = A0;
int waterPin = 3;
int windSpePin = 9;

long unsigned int lastActivationWater;
long unsigned int lastActivationWind;
int debounceTime = 15;

double temperatureValue = 0;
double pressureValue = 0;
double humidityValue = 0;
double gasValue = 0;

float waterAmaunt;
int lastWaterValue = 1;

int lastWindSpeValue;
float windCounter;
double windSpeed;

long _previousMillis = 0;
long previousMillis = 0;
long interval = 1000;

void setup() {
  // put your setup code here, to run once:
  pinMode (windDirPin, INPUT);
  pinMode (waterPin, INPUT);
  pinMode (windSpePin, INPUT);
  
  // Instantiere serial port med baud rate på 9600
  Serial.begin(9600);
}

String windDirection() {
  // Instantiere lokale variabler
  int windDirValue = analogRead(windDirPin);  
  String windDir;
  float windFloat;
  
       if (windDirValue> 940) windDir = "E", windFloat = 90;
  else if (windDirValue > 880) windDir = "SE", windFloat = 135;
  else if (windDirValue > 820) windDir = "ESE", windFloat = 112.5;
  else if (windDirValue > 780) windDir = "S", windFloat = 180;
  else if (windDirValue > 700) windDir = "SSE", windFloat = 157.5;
  else if (windDirValue > 630) windDir = "NE", windFloat = 45;
  else if (windDirValue > 590) windDir = "ENE", windFloat = 67.5;
  else if (windDirValue > 450) windDir = "SW", windFloat = 225;
  else if (windDirValue > 400) windDir = "SSW", windFloat = 202.5;
  else if (windDirValue > 280) windDir = "N", windFloat = 0;
  else if (windDirValue > 240) windDir = "NNE", windFloat = 22.5;
  else if (windDirValue > 180) windDir = "NW", windFloat = 315;
  else if (windDirValue > 120) windDir = "NNW", windFloat = 337.5;
  else if (windDirValue > 88) windDir = "W", windFloat = 270;
  else if (windDirValue > 75) windDir = "WSW", windFloat = 247.5;
  else windDir = "WNW", windFloat = 112.5;

  return (String) windDir + "\", \"windFloat\": \"" + windFloat;
}

float waterCounter() {
  // Instantiere lokale variabler
  int waterValue = digitalRead(waterPin);

  if((millis() - lastActivationWater) > debounceTime)   //if the time between the last buttonChange is greater than the debounceTime
  {
    lastActivationWater = millis();   //update lastPress                                                     
    if(waterValue == 0 && lastWaterValue == 1)    //if button is pressed and was released last change
    {      
      waterAmaunt += 0.2794;
      lastWaterValue = 0;    //record the lastButtonState
    }
  
    if(waterValue == 1 && lastWaterValue == 0)    //if button is not pressed, and was pressed last change
    {
      lastWaterValue = 1;    //record the lastButtonState
    }
  }

  return (float) waterAmaunt;
  
}
double windSpeedCalc() {
  // Instantiere lokale variabler
  int windSpeValue = digitalRead(windSpePin);
  unsigned long currentMillis = millis();
  
  if((millis() - lastActivationWind) > debounceTime)   // Vis tiden mellem siste aktivation er længere in debounceTime
  {
    lastActivationWind = millis();   //updatere lastActivation
    if(windSpeValue == 1 && lastWindSpeValue == 1)    //if button is pressed and was released last change
    {      
      windCounter += 1;
      lastWindSpeValue = 0;    //record the lastButtonState
    }
  
    if(windSpeValue == 0 && lastWindSpeValue == 0)    //if button is not pressed, and was pressed last change
    {
      lastWindSpeValue = 1;    //record the lastButtonState
    }
  }

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    windSpeed = windCounter * 0.6666672;

    windCounter = 0;
  }

  return (double) windSpeed;
}

void loop() {
  // put your main code here, to run repeatedly:
  double windSpeed = windSpeedCalc();
  String win = String(windSpeed, 2);
  String windDi = windDirection();
  float water = waterCounter();
  unsigned long _delay = millis();

  if (_delay - _previousMillis > 500) {
    _previousMillis = _delay;
    String output = "{\"windSpeed\": \"" + win + "\", \"windDir\": \"" + windDi + "\", \"waterAmount\": \""
    + water + "\", \"temperatureValue\" : \"" + temperatureValue + "\", \"pressureValue\" : \"" + pressureValue + 
    "\", \"humidityValue\" : \"" + humidityValue + "\", \"gasValue\" : \"" + gasValue + "\"}";
    Serial.println(output);
  }


 

}

This is the error we have in Raspberry PI:

(node:29598) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected token : in JSON at position 11
    at JSON.parse (<anonymous>)
    at ReadLineParser.<anonymous> (/home/pi/Desktop/test/app.js:54:24)
    at ReadLineParser.emit (events.js:400:28)
    at addChunk (internal/streams/readable.js:293:12)
    at readableAddChunk (internal/streams/readable.js:263:11)
    at ReadLineParser.Readable.push (internal/streams/readable.js:206:10)
    at ReadLineParser.Transform.push (internal/streams/transform.js:166:32)
    at ReadLineParser._transform (/home/pi/Desktop/test/node_modules/@serialport/parser-delimiter/lib/index.js:35:12)
    at ReadLineParser.Transform._read (internal/streams/transform.js:205:10)
    at ReadLineParser.Transform._write (internal/streams/transform.js:193:12)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:29598) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:29598) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

To be clear, the program does work! But only in 2-3 times out of 10.

Thanks in advance!

Andreas.

Welcome to the forum

Try printing the output String in the Arduino code

Does it look like you expect it to under all conditions ?

No, it cuts the output String and then it works after that.

 "0. : "0.00", "gasValue" : "0.00"}

, "waterAmount": "0.00", "temperatureValue" : "0.00", "pressureValue" : "0.00", "humidityValue" : "0.00", "gasValue" : "0.00"}

, "waterAmount": "0.00", "temperatureValue" : "0.00", "pressureValue" : "0.00", "humidityValue" : "0.00", "gasValue" : "0.00"}

{"windSpeed": "0.00", "windDir": "NE", "windFloat": "45.00", "waterAmount": "0.00", "temperatureValue" : "0.00", "pressureValue" : "0.00", "humidityValue" : "0.00", "gasValue" : "0.00"}

{"windSpeed": "0.00", "windDir": "NE", "windFloat": "45.00", "waterAmount": "0.00", "temperatureValue" : "0.00", "pressureValue" : "0.00", "humidityValue" : "0.00", "gasValue" : "0.00"}

{"windSpeed": "0.00", "windDir": "NE", "windFloat": "45.00", "waterAmount": "0.00", "temperatureValue" : "0.00", "pressureValue" : "0.00", "humidityValue" : "0.00", "gasValue" : "0.00"}


I would just print the data, without building a String by concatenation,
that is only used to be printed.

We have also set up an API which uses that JSON data. Our API works fine. Would that not ruin our API?

The value of output is going nowhere.

Its printed to our raspberry pi through the serial port. We then recieve the data and parses it into JSON.


    var socket = io();

    socket.on('data', function (data) {
      console.log(data);

      var obj = JSON.parse(data)

      windSpeed = obj.windSpeed;
      windDir = obj.windDir;
      windFloat = obj.windFloat;
      waterAmount = obj.waterAmount;

Why do you think you would have to send the stuff with one call?

Your

slows transmission down to about 1000 chars a second.

The receiving side is not able to distinguish one call from many calls,
which will be over probably before the first chars have made it to the Raspi.

Your concatenation will not work on small Arduinos, they just don't have the memory to
cope with such a bad memory request sequence.

Thanks for your help. I'm like "really" new to this. I joined this project a little after they built the Arduino, so today is my first day learning programming in Arduino. I read about the Serial.begin(9600);

My colleague said earlier that we would need the string concatenation in order for the JS application on rasp pi in order to understand the data which I'm a little unsure about.
What would you suggest that I do?

Just try printing all the fields one after another, best without any concatenations.

Which Arduino are you using?

We're using the arduino uno

Then all that concatenation is asking for trouble as @Whandall pointed out.

So you would like us to print it as 8 different strings one after another, without doing it as a whole string with concatenations?

No, you would like to do something like that, because it will work.

Forget about building any strings, just print one thing after another,
be it constant chars, or variables.

Serial is buffered, it will collect all the stuff you print, and will only block, if that buffer gets full.

Our problem in that case would be that we would need the variables to be parsed into JSON in our application on the PI. If we print all the stuff one after one, how would the JSON know that it belong together?

For now works like this, if we sent it one after one, would we be able to still parse the data correct?


var SerialPort = require('serialport');
const parsers = SerialPort.parsers;

const parser = new parsers.Readline({
    delimiter: '\r\n'
});

var port = new SerialPort('/dev/ttyACM0', {
    baudRate: 9600,
    dataBits: 8,
    parity: 'none',
    stopBits: 1,
    flowControl: false
});

port.pipe(parser);

var app = http.createServer(function (req, res) {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end(index);
});

var io = require('socket.io').listen(app);


io.on('connection', function (socket) {

    console.log('Node is listening to port');

});

con.connect(function (err) {

    parser.on('data', function (data) {

        //console.log('Received data from port: ' + data);

        io.emit('data', data)
        jsonObj = JSON.parse(data);

        windSpeed = jsonObj.windSpeed; 
        windDir = jsonObj.windDir;
        windFloat = jsonObj.windFloat
        waterAmount = jsonObj.waterAmount;
        temperatureValue = jsonObj.temperatureValue;
        pressureValue = jsonObj.pressureValue;
        humidityValue = jsonObj.humidityValue;
        gasValue = jsonObj.gasValue

It will deduct it from the last CR/LF in the stream and/or the .5 second pause in the stream.

You are arguing longer, than the change would take, are you allergic to hints?

No, and im not trying to argue. I'm just trying to learn. I literally has 4 hours of knowledge with arduinos. Im just trying to figure out how it works
Sorry for that

Your serial port is sending ~960 characters a second. It's the bottleneck here. The Arduino can push characters into the output buffer far far faster than that. So as far as the Pi is concerned, it'll see the same stream of data whether you gather it into a string and print or whether you send one character at a time.

1 Like